{"has_methods_read":true,"is_self_destructed":false,"has_custom_methods_write":false,"file_path":"contracts/musd/EnclaveDebtManager.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.33;\n\nimport {Initializable} from \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\nimport {AccessControlEnumerableUpgradeable} from \"@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol\";\nimport {ReentrancyGuardUpgradeable} from \"@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol\";\nimport {PausableUpgradeable} from \"@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol\";\n\nimport {IVotingEscrow} from \"../interfaces/IVotingEscrow.sol\";\nimport {IEnclaveDebtManager} from \"./IEnclaveDebtManager.sol\";\nimport {FeeAccrual, FeeAccrualMath, PositionFeeAccrual} from \"./FeeAccrualMath.sol\";\nimport {IPriceFeed} from \"./IPriceFeed.sol\";\nimport {IMUSD} from \"./IMUSD.sol\";\nimport {SafeCastLibrary} from \"../libraries/SafeCastLibrary.sol\";\n\n/// @title EnclaveDebtManager\n/// @notice On-chain debt accounting for Enclave-managed MUSD minting.\n///         Authorized Enclaves open positions that mint MUSD to\n///         borrowers, with per-position tracking of principal, interest rates,\n///         originator fees, and the collateral backing each loan.\n///         Positions are backed by pledged veBTC NFTs whose locked BTC\n///         amount serves as collateral. Because the veBTC NFTs are held\n///         inside the calling Enclave, they cannot be transferred without\n///         authorization, effectively locking the collateral.\n/// @dev Roles:\n///      - DEFAULT_ADMIN_ROLE and GOVERNANCE_ROLE are held by governance.\n///        Governance manages Enclaves and protocol parameters, and can\n///        unpause the contract.\n///      - PAUSER_ROLE holders can pause the contract. The role admin for\n///        PAUSER_ROLE is GOVERNANCE_ROLE.\n///      - ENCLAVE_ROLE holders (Enclave contracts) can open positions and\n///        manage them. The role admin for ENCLAVE_ROLE is GOVERNANCE_ROLE.\ncontract EnclaveDebtManager is\n    IEnclaveDebtManager,\n    Initializable,\n    AccessControlEnumerableUpgradeable,\n    ReentrancyGuardUpgradeable,\n    PausableUpgradeable\n{\n    // -----------------------------------------------------------------------\n    //  Constants\n    // -----------------------------------------------------------------------\n\n    bytes32 public constant GOVERNANCE_ROLE = keccak256(\"GOVERNANCE_ROLE\");\n    bytes32 public constant ENCLAVE_ROLE = keccak256(\"ENCLAVE_ROLE\");\n    bytes32 public constant PAUSER_ROLE = keccak256(\"PAUSER_ROLE\");\n    uint256 public constant MAX_PLEDGED_VEBTC = 20;\n    uint256 public constant MIN_MINIMUM_CR = 1.1e18;\n\n    using FeeAccrualMath for FeeAccrual;\n    using PositionFeeAccrual for Position;\n    using SafeCastLibrary for int128;\n\n    // -----------------------------------------------------------------------\n    //  Storage\n    // -----------------------------------------------------------------------\n\n    /// @inheritdoc IEnclaveDebtManager\n    IMUSD public musd;\n\n    /// @inheritdoc IEnclaveDebtManager\n    IVotingEscrow public veBTC;\n\n    /// @inheritdoc IEnclaveDebtManager\n    IPriceFeed public priceFeed;\n\n    /// @inheritdoc IEnclaveDebtManager\n    address public pcv;\n\n    /// @dev All positions, keyed by caller-provided ID.\n    mapping(bytes32 => Position) private positions;\n\n    /// @dev Reverse lookup: veBTC token ID -> position ID it is pledged to.\n    mapping(uint256 => bytes32) private veBtcPosition;\n\n    /// @inheritdoc IEnclaveDebtManager\n    uint256 public totalPrincipal;\n\n    /// @inheritdoc IEnclaveDebtManager\n    uint256 public totalMintedDebt;\n\n    /// @dev System-wide interest fee accumulator. The numerator is the sum of\n    ///      (principal * interestRate) across all active positions, used to\n    ///      compute aggregate interest in O(1). lastUpdateTime is the timestamp\n    ///      of the most recent accrual.\n    FeeAccrual public interest;\n\n    /// @inheritdoc IEnclaveDebtManager\n    uint256 public totalInterestMinted;\n\n    /// @dev Per-originator fee accumulators. Each originator gets its own\n    ///      FeeAccrual whose numerator is the sum of\n    ///      (principal * originatorFeeRate) across all active positions\n    ///      belonging to that originator, used to compute per-originator fees\n    ///      in O(1). lastUpdateTime is the timestamp of the most recent\n    ///      accrual.\n    mapping(address => FeeAccrual) public originatorFees;\n\n    /// @inheritdoc IEnclaveDebtManager\n    uint256 public totalOriginatorFeeMinted;\n\n    /// @inheritdoc IEnclaveDebtManager\n    mapping(address => uint256) public originatorFeeMinted;\n\n    /// @inheritdoc IEnclaveDebtManager\n    uint256 public totalDebtBurned;\n\n    /// @notice The combined fee accumulator used for O(1) total-debt queries.\n    ///         Its numerator is the sum of\n    ///         principal_i * (interestRate_i + originatorFeeRate_i) across all\n    ///         active positions. This accumulator only grows.\n    FeeAccrual public combinedFees;\n\n    /// @dev Cumulative fees flushed from the combined fee accumulator. Does\n    ///      not include fees accrued since the last flush - use\n    ///      getTotalOutstandingDebt() for a complete view. This counter only\n    ///      grows.\n    uint256 public totalFeesStored;\n\n    /// @dev Cumulative fees settled (paid) by borrowers through repayment.\n    uint256 public totalFeeSettled;\n\n    /// @inheritdoc IEnclaveDebtManager\n    uint16 public maxRate;\n\n    /// @inheritdoc IEnclaveDebtManager\n    uint256 public mintCap;\n\n    // -----------------------------------------------------------------------\n    //  Modifiers\n    // -----------------------------------------------------------------------\n\n    /// @dev Require the caller to hold ENCLAVE_ROLE, the position to be\n    ///      active, and the position to be owned by the calling Enclave.\n    modifier onlyActivePositionEnclave(bytes32 _positionId) {\n        _checkRole(ENCLAVE_ROLE);\n        Position storage pos = positions[_positionId];\n        if (pos.status != Status.active) {\n            revert PositionNotActive(_positionId);\n        }\n        if (pos.enclave != msg.sender) {\n            revert NotPositionEnclave(_positionId);\n        }\n        _;\n    }\n\n    // -----------------------------------------------------------------------\n    //  Initializer\n    // -----------------------------------------------------------------------\n\n    /// @custom:oz-upgrades-unsafe-allow constructor\n    constructor() {\n        _disableInitializers();\n    }\n\n    /// @notice Initialize the EnclaveDebtManager.\n    /// @param _musd The MUSD stablecoin address. This contract must be added\n    ///        to MUSD's mintList before positions can be opened.\n    /// @param _veBTC The VotingEscrow (veBTC) contract address.\n    /// @param _priceFeed The price feed contract address. The price feed MUST\n    ///        protect against stale prices on its own.\n    /// @param _governance The governance address. Receives DEFAULT_ADMIN_ROLE\n    ///        and GOVERNANCE_ROLE, and can grant/revoke ENCLAVE_ROLE.\n    /// @param _pauser The address that receives PAUSER_ROLE for fast\n    ///        emergency pausing.\n    /// @param _pcv The PCV (Protocol Controlled Value) address that receives\n    ///        minted interest.\n    /// @param _enclaves Initial set of Enclave addresses.\n    /// @param _maxRate Initial maximum combined rate (interestRate +\n    ///        originatorFeeRate) in basis points.\n    /// @param _mintCap Initial MUSD mint cap.\n    function initialize(\n        address _musd,\n        address _veBTC,\n        address _priceFeed,\n        address _governance,\n        address _pauser,\n        address _pcv,\n        address[] calldata _enclaves,\n        uint16 _maxRate,\n        uint256 _mintCap\n    ) external initializer {\n        if (_musd == address(0)) revert ZeroAddress();\n        if (_veBTC == address(0)) revert ZeroAddress();\n        if (_priceFeed == address(0)) revert ZeroAddress();\n        if (_governance == address(0)) revert ZeroAddress();\n        if (_pauser == address(0)) revert ZeroAddress();\n        if (_pcv == address(0)) revert ZeroAddress();\n\n        __AccessControlEnumerable_init();\n        __ReentrancyGuard_init();\n        __Pausable_init();\n\n        musd = IMUSD(_musd);\n        veBTC = IVotingEscrow(_veBTC);\n        priceFeed = IPriceFeed(_priceFeed);\n        pcv = _pcv;\n        interest.lastUpdateTime = block.timestamp;\n        combinedFees.lastUpdateTime = block.timestamp;\n\n        _grantRole(DEFAULT_ADMIN_ROLE, _governance);\n        _grantRole(GOVERNANCE_ROLE, _governance);\n        _grantRole(PAUSER_ROLE, _pauser);\n        _setRoleAdmin(ENCLAVE_ROLE, GOVERNANCE_ROLE);\n        _setRoleAdmin(PAUSER_ROLE, GOVERNANCE_ROLE);\n\n        for (uint256 i = 0; i < _enclaves.length; ++i) {\n            _grantRole(ENCLAVE_ROLE, _enclaves[i]);\n        }\n\n        maxRate = _maxRate;\n        mintCap = _mintCap;\n        emit MaxRateSet(_maxRate);\n        emit MintCapSet(_mintCap);\n    }\n\n    // -----------------------------------------------------------------------\n    //  Views\n    // -----------------------------------------------------------------------\n\n    /// @inheritdoc IEnclaveDebtManager\n    function getPosition(\n        bytes32 positionId\n    ) external view returns (Position memory) {\n        return positions[positionId];\n    }\n\n    /// @inheritdoc IEnclaveDebtManager\n    function getVeBtcPositionId(\n        uint256 tokenId\n    ) external view returns (bytes32) {\n        return veBtcPosition[tokenId];\n    }\n\n    /// @inheritdoc IEnclaveDebtManager\n    function getPledgedVeBtc(\n        bytes32 positionId\n    ) external view returns (uint256[] memory) {\n        return positions[positionId].pledgedVeBtc;\n    }\n\n    /// @inheritdoc IEnclaveDebtManager\n    function getPositionCollateral(\n        bytes32 positionId\n    ) public view returns (uint256) {\n        uint256[] storage tokenIds = positions[positionId].pledgedVeBtc;\n        uint256 total = 0;\n        for (uint256 i = 0; i < tokenIds.length; ++i) {\n            total += veBTC.locked(tokenIds[i]).amount.toUint256();\n        }\n        return total;\n    }\n\n    /// @inheritdoc IEnclaveDebtManager\n    function getPositionCR(bytes32 positionId) public view returns (uint256) {\n        uint256 collateral = getPositionCollateral(positionId);\n        uint256 price = priceFeed.fetchPrice();\n        (, , , uint256 debt) = getPositionDebt(positionId);\n        if (debt == 0) return type(uint256).max;\n        return (collateral * price) / debt;\n    }\n\n    /// @inheritdoc IEnclaveDebtManager\n    function getPositionDebt(\n        bytes32 positionId\n    )\n        public\n        view\n        returns (\n            uint256 principal,\n            uint256 accruedInterest,\n            uint256 accruedOriginatorFee,\n            uint256 totalDebt\n        )\n    {\n        Position storage pos = positions[positionId];\n        principal = pos.principal;\n        if (principal == 0) return (0, 0, 0, 0);\n\n        accruedInterest = pos.totalAccruedInterest();\n        accruedOriginatorFee = pos.totalAccruedOriginatorFee();\n\n        // Then sum the principal and most recent values of system fees to\n        // calculate the total position's debt.\n        totalDebt = principal + accruedInterest + accruedOriginatorFee;\n    }\n\n    /// @inheritdoc IEnclaveDebtManager\n    function getPositionHealthStatus(\n        bytes32 _positionId\n    )\n        external\n        view\n        returns (\n            uint256 currentCR,\n            uint256 warningCR,\n            uint256 minimumCR,\n            bool isBelowWarning,\n            bool isBelowMinimum\n        )\n    {\n        Position storage pos = positions[_positionId];\n        currentCR = getPositionCR(_positionId);\n        warningCR = pos.warningCR;\n        minimumCR = pos.minimumCR;\n        isBelowWarning = currentCR < warningCR;\n        isBelowMinimum = currentCR < minimumCR;\n    }\n\n    /// @inheritdoc IEnclaveDebtManager\n    function getAccruedInterest() public view returns (uint256) {\n        return interest.accrued();\n    }\n\n    /// @inheritdoc IEnclaveDebtManager\n    function getAccruedOriginatorFee(\n        address _originator\n    ) public view returns (uint256) {\n        return originatorFees[_originator].accrued();\n    }\n\n    /// @inheritdoc IEnclaveDebtManager\n    function getTotalOutstandingDebt() public view returns (uint256) {\n        uint256 fees = totalFeesStored + combinedFees.accrued();\n        // The system-wide accumulator and the per-position fee calculations use\n        // independent integer divisions, so rounding can cause totalFeeSettled\n        // to exceed fees by a few wei. Note this can only happen right after a\n        // repayment, when the pending accrual is near zero.\n        uint256 unsettledFees = fees > totalFeeSettled\n            ? fees - totalFeeSettled\n            : 0;\n        return totalPrincipal + unsettledFees;\n    }\n\n    // -----------------------------------------------------------------------\n    //  Fee accrual\n    // -----------------------------------------------------------------------\n\n    /// @inheritdoc IEnclaveDebtManager\n    function accrueInterest() external whenNotPaused {\n        _accrueInterest();\n    }\n\n    /// @inheritdoc IEnclaveDebtManager\n    function accrueOriginatorFee(address _originator) external whenNotPaused {\n        _accrueOriginatorFee(_originator);\n    }\n\n    // -----------------------------------------------------------------------\n    //  Governance\n    // -----------------------------------------------------------------------\n\n    /// @inheritdoc IEnclaveDebtManager\n    function pause() external onlyRole(PAUSER_ROLE) {\n        _pause();\n    }\n\n    /// @inheritdoc IEnclaveDebtManager\n    function unpause() external onlyRole(GOVERNANCE_ROLE) {\n        _unpause();\n    }\n\n    /// @inheritdoc IEnclaveDebtManager\n    function setMaxRate(uint16 _maxRate) external onlyRole(GOVERNANCE_ROLE) {\n        maxRate = _maxRate;\n        emit MaxRateSet(_maxRate);\n    }\n\n    /// @inheritdoc IEnclaveDebtManager\n    function setMintCap(uint256 _cap) external onlyRole(GOVERNANCE_ROLE) {\n        mintCap = _cap;\n        emit MintCapSet(_cap);\n    }\n\n    // -----------------------------------------------------------------------\n    //  Enclave actions\n    // -----------------------------------------------------------------------\n\n    /// @inheritdoc IEnclaveDebtManager\n    function openPosition(\n        bytes32 _positionId,\n        address _borrower,\n        address _originator,\n        uint256 _debtAmount,\n        uint16 _interestRate,\n        uint16 _originatorFeeRate,\n        uint256[] calldata _pledgedVeBtcIds,\n        uint256 _warningCR,\n        uint256 _minimumCR\n    ) external onlyRole(ENCLAVE_ROLE) whenNotPaused nonReentrant {\n        // Accrue pending fees before adding the new position's contribution\n        // to the numerators.\n        _accrueAllFees(_originator);\n\n        if (_positionId == bytes32(0)) revert ZeroPositionId();\n        if (_borrower == address(0)) revert ZeroAddress();\n        if (_originator == address(0)) revert ZeroAddress();\n        if (_debtAmount == 0) revert ZeroAmount();\n        if (positions[_positionId].status != Status.nonExistent) {\n            revert PositionAlreadyExists(_positionId);\n        }\n        if (_pledgedVeBtcIds.length == 0) revert EmptyPledgedVeBtc();\n        if (_pledgedVeBtcIds.length > MAX_PLEDGED_VEBTC) {\n            // Defense-in-depth to protect iteration calculating CR.\n            revert TooManyPledgedVeBtc(_pledgedVeBtcIds.length);\n        }\n\n        // avoid stack too deep\n        {\n            // Enforce max combined rate.\n            uint32 combinedRate = uint32(_interestRate) +\n                uint32(_originatorFeeRate);\n            if (combinedRate > maxRate) {\n                revert RateExceedsMaxRate(combinedRate, maxRate);\n            }\n        }\n\n        // Enforce mint cap on net outstanding principal.\n        if (totalPrincipal + _debtAmount > mintCap) {\n            revert MintCapExceeded(totalPrincipal + _debtAmount, mintCap);\n        }\n\n        // Enforce CR-threshold invariants.\n        if (_minimumCR < MIN_MINIMUM_CR) {\n            revert MinimumCRTooLow(_minimumCR);\n        }\n        if (_warningCR <= _minimumCR) {\n            revert WarningCRNotAboveMinimumCR(_warningCR, _minimumCR);\n        }\n\n        for (uint256 i = 0; i < _pledgedVeBtcIds.length; ++i) {\n            // Validate ownership and uniqueness of each pledged veBTC token.\n            uint256 tokenId = _pledgedVeBtcIds[i];\n            if (veBTC.ownerOf(tokenId) != msg.sender) {\n                revert NotTokenOwner(tokenId);\n            }\n            bytes32 existingPosition = veBtcPosition[tokenId];\n            if (existingPosition != bytes32(0)) {\n                revert TokenAlreadyPledged(tokenId, existingPosition);\n            }\n\n            // If valid and unique, store the reverse mapping to the position\n            veBtcPosition[tokenId] = _positionId;\n        }\n\n        // Store the position.\n        positions[_positionId] = Position({\n            principal: _debtAmount,\n            storedInterest: 0,\n            storedOriginatorFee: 0,\n            lastUpdateTimestamp: block.timestamp,\n            interestRate: _interestRate,\n            originatorFeeRate: _originatorFeeRate,\n            warningCR: _warningCR,\n            minimumCR: _minimumCR,\n            enclave: msg.sender,\n            borrower: _borrower,\n            originator: _originator,\n            status: Status.active,\n            pledgedVeBtc: _pledgedVeBtcIds\n        });\n\n        // avoid stack too deep\n        {\n            // Enforce minimum collateralization ratio.\n            uint256 cr = getPositionCR(_positionId);\n            if (cr < _minimumCR) {\n                revert InsufficientCollateral(_positionId, cr, _minimumCR);\n            }\n        }\n\n        _accountNewDebt(\n            _debtAmount,\n            _originator,\n            _interestRate,\n            _originatorFeeRate\n        );\n\n        musd.mint(_borrower, _debtAmount);\n\n        emit PositionOpened(\n            _positionId,\n            msg.sender,\n            _borrower,\n            _debtAmount,\n            _originator,\n            _interestRate,\n            _originatorFeeRate,\n            _warningCR,\n            _minimumCR,\n            _pledgedVeBtcIds\n        );\n    }\n\n    /// @inheritdoc IEnclaveDebtManager\n    function increaseDebt(\n        bytes32 _positionId,\n        uint256 _additionalDebt\n    )\n        external\n        onlyActivePositionEnclave(_positionId)\n        whenNotPaused\n        nonReentrant\n    {\n        if (_additionalDebt == 0) revert ZeroAmount();\n\n        Position storage pos = positions[_positionId];\n\n        // Enforce mint cap.\n        if (totalPrincipal + _additionalDebt > mintCap) {\n            revert MintCapExceeded(totalPrincipal + _additionalDebt, mintCap);\n        }\n\n        // Accrue pending system fees before adding the updated position's\n        // contribution to the numerators.\n        _accrueAllFees(pos.originator);\n\n        // Snapshot accrued position fees before changing principal so that fees\n        // accrued on the old principal are not recomputed on the new one.\n        pos.accrueFees();\n\n        pos.principal += _additionalDebt;\n\n        _accountNewDebt(\n            _additionalDebt,\n            pos.originator,\n            pos.interestRate,\n            pos.originatorFeeRate\n        );\n\n        // Enforce minimum collateralization ratio.\n        uint256 cr = getPositionCR(_positionId);\n        if (cr < pos.minimumCR) {\n            revert InsufficientCollateral(_positionId, cr, pos.minimumCR);\n        }\n\n        musd.mint(pos.borrower, _additionalDebt);\n\n        emit DebtIncreased(_positionId, _additionalDebt, pos.principal);\n    }\n\n    /// @inheritdoc IEnclaveDebtManager\n    function addPledgedVeBtc(\n        bytes32 _positionId,\n        uint256[] calldata _tokenIdsToAdd\n    )\n        external\n        onlyActivePositionEnclave(_positionId)\n        whenNotPaused\n        nonReentrant\n    {\n        if (_tokenIdsToAdd.length == 0) revert EmptyPledgedVeBtc();\n\n        Position storage pos = positions[_positionId];\n        if (\n            pos.pledgedVeBtc.length + _tokenIdsToAdd.length > MAX_PLEDGED_VEBTC\n        ) {\n            // Defense-in-depth to protect iteration calculating CR.\n            revert TooManyPledgedVeBtc(\n                pos.pledgedVeBtc.length + _tokenIdsToAdd.length\n            );\n        }\n\n        for (uint256 i = 0; i < _tokenIdsToAdd.length; ++i) {\n            uint256 tokenId = _tokenIdsToAdd[i];\n            if (veBTC.ownerOf(tokenId) != msg.sender) {\n                revert NotTokenOwner(tokenId);\n            }\n            bytes32 existingPosition = veBtcPosition[tokenId];\n            if (existingPosition != bytes32(0)) {\n                revert TokenAlreadyPledged(tokenId, existingPosition);\n            }\n\n            veBtcPosition[tokenId] = _positionId;\n            pos.pledgedVeBtc.push(tokenId);\n        }\n\n        emit PledgedVeBtcAdded(_positionId, _tokenIdsToAdd, pos.pledgedVeBtc);\n    }\n\n    /// @inheritdoc IEnclaveDebtManager\n    function removePledgedVeBtc(\n        bytes32 _positionId,\n        uint256[] calldata _tokenIdsToRemove\n    )\n        external\n        onlyActivePositionEnclave(_positionId)\n        whenNotPaused\n        nonReentrant\n    {\n        if (_tokenIdsToRemove.length == 0) revert EmptyPledgedVeBtc();\n\n        Position storage pos = positions[_positionId];\n\n        uint256[] storage pledged = pos.pledgedVeBtc;\n\n        for (uint256 i = 0; i < _tokenIdsToRemove.length; ++i) {\n            uint256 tokenId = _tokenIdsToRemove[i];\n            if (veBtcPosition[tokenId] != _positionId) {\n                revert TokenNotPledged(tokenId, _positionId);\n            }\n\n            // Find the token in the array and swap-and-pop.\n            uint256 len = pledged.length;\n            for (uint256 j = 0; j < len; ++j) {\n                if (pledged[j] == tokenId) {\n                    pledged[j] = pledged[len - 1];\n                    pledged.pop();\n                    break;\n                }\n            }\n\n            delete veBtcPosition[tokenId];\n        }\n\n        // Enforce minimum collateralization ratio after all removals.\n        uint256 cr = getPositionCR(_positionId);\n        if (cr < pos.minimumCR) {\n            revert InsufficientCollateral(_positionId, cr, pos.minimumCR);\n        }\n\n        emit PledgedVeBtcRemoved(\n            _positionId,\n            _tokenIdsToRemove,\n            pos.pledgedVeBtc\n        );\n    }\n\n    /// @inheritdoc IEnclaveDebtManager\n    function setPositionCRThresholds(\n        bytes32 _positionId,\n        uint256 _warningCR,\n        uint256 _minimumCR\n    )\n        external\n        onlyActivePositionEnclave(_positionId)\n        whenNotPaused\n        nonReentrant\n    {\n        // Enforce CR-threshold invariants.\n        if (_minimumCR < MIN_MINIMUM_CR) {\n            revert MinimumCRTooLow(_minimumCR);\n        }\n        if (_warningCR <= _minimumCR) {\n            revert WarningCRNotAboveMinimumCR(_warningCR, _minimumCR);\n        }\n\n        Position storage pos = positions[_positionId];\n        pos.warningCR = _warningCR;\n        pos.minimumCR = _minimumCR;\n\n        // Enforce minimum collateralization ratio. Without this enforcement,\n        // it would be possible to self-force liquidation despite of the\n        // previous agreement on the minimum CR. Adjust the position first, then\n        // modify the CR.\n        uint256 cr = getPositionCR(_positionId);\n        if (cr < _minimumCR) {\n            revert InsufficientCollateral(_positionId, cr, _minimumCR);\n        }\n\n        emit PositionCRThresholdsSet(_positionId, _warningCR, _minimumCR);\n    }\n\n    /// @inheritdoc IEnclaveDebtManager\n    function repay(\n        bytes32 _positionId,\n        uint256 _amount\n    )\n        external\n        onlyActivePositionEnclave(_positionId)\n        whenNotPaused\n        nonReentrant\n    {\n        _repay(_positionId, _amount);\n    }\n\n    /// @inheritdoc IEnclaveDebtManager\n    function repayAll(\n        bytes32 _positionId\n    )\n        external\n        onlyActivePositionEnclave(_positionId)\n        whenNotPaused\n        nonReentrant\n        returns (uint256 amount)\n    {\n        Position storage pos = positions[_positionId];\n\n        amount =\n            pos.principal +\n            pos.totalAccruedInterest() +\n            pos.totalAccruedOriginatorFee();\n\n        _repay(_positionId, amount);\n    }\n\n    function _repay(bytes32 _positionId, uint256 _amount) private {\n        if (_amount == 0) revert ZeroAmount();\n\n        Position storage pos = positions[_positionId];\n\n        // Accrue and mint all system-wide fees to date.\n        _accrueAllFees(pos.originator);\n\n        // Compute this position's accrued fees before settling.\n        uint256 totalFees = pos.totalAccruedInterest() +\n            pos.totalAccruedOriginatorFee();\n\n        pos.settleFees();\n        totalFeeSettled += totalFees;\n\n        // Fees are deducted from _amount first; the remainder reduces\n        // the principal.\n        if (_amount < totalFees) {\n            revert RepaymentInsufficientForFees(\n                _positionId,\n                _amount,\n                totalFees\n            );\n        }\n        uint256 principalRepayment = _amount - totalFees;\n\n        if (principalRepayment > pos.principal) {\n            revert RepaymentExceedsPrincipal(\n                _positionId,\n                principalRepayment,\n                pos.principal\n            );\n        }\n\n        musd.burn(msg.sender, _amount);\n\n        pos.principal -= principalRepayment;\n        _accountRemovedDebt(\n            principalRepayment,\n            pos.originator,\n            pos.interestRate,\n            pos.originatorFeeRate\n        );\n\n        if (pos.principal == 0) {\n            pos.status = Status.closedByRepayment;\n\n            // Release pledged veBTC so the tokens can be reused as collateral.\n            uint256[] storage tokenIds = pos.pledgedVeBtc;\n            for (uint256 i = 0; i < tokenIds.length; ++i) {\n                delete veBtcPosition[tokenIds[i]];\n            }\n            delete pos.pledgedVeBtc;\n        }\n\n        emit DebtRepaid(_positionId, _amount, pos.principal);\n\n        if (pos.status == Status.closedByRepayment) {\n            emit PositionClosed(_positionId);\n        }\n    }\n\n    /// @inheritdoc IEnclaveDebtManager\n    function setPositionInterestRate(\n        bytes32 _positionId,\n        uint16 _newInterestRate\n    ) external onlyRole(ENCLAVE_ROLE) whenNotPaused nonReentrant {\n        Position storage pos = positions[_positionId];\n        if (pos.status != Status.active) {\n            revert PositionNotActive(_positionId);\n        }\n        if (pos.enclave != msg.sender) {\n            revert NotPositionEnclave(_positionId);\n        }\n\n        // Enforce max combined rate.\n        uint32 combinedRate = uint32(_newInterestRate) +\n            uint32(pos.originatorFeeRate);\n        if (combinedRate > maxRate) {\n            revert RateExceedsMaxRate(combinedRate, maxRate);\n        }\n\n        // Accrue pending system fees at the old numerators.\n        _accrueAllFees(pos.originator);\n\n        // Snapshot per-position fees at the old rate.\n        pos.accrueFees();\n\n        uint16 oldRate = pos.interestRate;\n\n        _accountNewInterestRate(pos.principal, oldRate, _newInterestRate);\n\n        pos.interestRate = _newInterestRate;\n\n        emit PositionInterestRateSet(_positionId, oldRate, _newInterestRate);\n    }\n\n    /// @inheritdoc IEnclaveDebtManager\n    function setPositionOriginatorFeeRate(\n        bytes32 _positionId,\n        uint16 _newOriginatorFeeRate\n    ) external onlyRole(ENCLAVE_ROLE) whenNotPaused nonReentrant {\n        Position storage pos = positions[_positionId];\n        if (pos.status != Status.active) {\n            revert PositionNotActive(_positionId);\n        }\n        if (pos.enclave != msg.sender) {\n            revert NotPositionEnclave(_positionId);\n        }\n\n        // Enforce max combined rate.\n        uint32 combinedRate = uint32(pos.interestRate) +\n            uint32(_newOriginatorFeeRate);\n        if (combinedRate > maxRate) {\n            revert RateExceedsMaxRate(combinedRate, maxRate);\n        }\n\n        // Accrue pending system fees at the old numerators.\n        _accrueAllFees(pos.originator);\n\n        // Snapshot per-position fees at the old rate.\n        pos.accrueFees();\n\n        uint16 oldRate = pos.originatorFeeRate;\n\n        _accountNewOriginatorFeeRate(\n            pos.principal,\n            pos.originator,\n            oldRate,\n            _newOriginatorFeeRate\n        );\n\n        pos.originatorFeeRate = _newOriginatorFeeRate;\n\n        emit PositionOriginatorFeeRateSet(\n            _positionId,\n            oldRate,\n            _newOriginatorFeeRate\n        );\n    }\n\n    // -----------------------------------------------------------------------\n    //  Internals\n    // -----------------------------------------------------------------------\n\n    /// @dev Accrue all system-wide fee accumulators for a given originator,\n    ///      minting MUSD where applicable. Must be called before any operation\n    ///      that changes accumulator numerators (open, increase, repay).\n    function _accrueAllFees(address _originator) internal {\n        _accrueInterest();\n        _accrueOriginatorFee(_originator);\n        _snapshotCombinedFees();\n    }\n\n    /// @dev Update all system-level debt counters after new principal is added\n    ///      to a position. Called by both openPosition and increaseDebt.\n    function _accountNewDebt(\n        uint256 _amount,\n        address _originator,\n        uint16 _interestRate,\n        uint16 _originatorFeeRate\n    ) internal {\n        totalPrincipal += _amount;\n        totalMintedDebt += _amount;\n\n        interest.addPrincipal(_amount, _interestRate);\n        originatorFees[_originator].addPrincipal(_amount, _originatorFeeRate);\n        combinedFees.addPrincipal(_amount, _interestRate);\n        combinedFees.addPrincipal(_amount, _originatorFeeRate);\n    }\n\n    /// @dev Update all system-level debt counters after principal is removed\n    ///      from a position. Called by repay.\n    function _accountRemovedDebt(\n        uint256 _amount,\n        address _originator,\n        uint16 _interestRate,\n        uint16 _originatorFeeRate\n    ) internal {\n        totalPrincipal -= _amount;\n        totalDebtBurned += _amount;\n\n        interest.removePrincipal(_amount, _interestRate);\n        originatorFees[_originator].removePrincipal(\n            _amount,\n            _originatorFeeRate\n        );\n        combinedFees.removePrincipal(_amount, _interestRate);\n        combinedFees.removePrincipal(_amount, _originatorFeeRate);\n    }\n\n    /// @dev Swap a position's interest-rate contribution in the system-wide\n    ///      accumulators. Called by setPositionInterestRate.\n    function _accountNewInterestRate(\n        uint256 _principal,\n        uint16 _oldRate,\n        uint16 _newRate\n    ) internal {\n        interest.removePrincipal(_principal, _oldRate);\n        interest.addPrincipal(_principal, _newRate);\n        combinedFees.removePrincipal(_principal, _oldRate);\n        combinedFees.addPrincipal(_principal, _newRate);\n    }\n\n    /// @dev Swap a position's originator-fee-rate contribution in the\n    ///      system-wide accumulators. Called by setPositionOriginatorFeeRate.\n    function _accountNewOriginatorFeeRate(\n        uint256 _principal,\n        address _originator,\n        uint16 _oldRate,\n        uint16 _newRate\n    ) internal {\n        originatorFees[_originator].removePrincipal(_principal, _oldRate);\n        originatorFees[_originator].addPrincipal(_principal, _newRate);\n        combinedFees.removePrincipal(_principal, _oldRate);\n        combinedFees.addPrincipal(_principal, _newRate);\n    }\n\n    /// @dev Materialize accrued interest by minting MUSD to the PCV address.\n    function _accrueInterest() internal {\n        uint256 accruedInterest = interest.accrue();\n\n        if (accruedInterest > 0) {\n            totalInterestMinted += accruedInterest;\n            musd.mint(pcv, accruedInterest);\n            emit InterestAccrued(accruedInterest, totalInterestMinted);\n        }\n    }\n\n    /// @dev Materialize accrued originator fee for a specific originator by\n    ///      minting MUSD to their address.\n    function _accrueOriginatorFee(address _originator) internal {\n        uint256 accrued = originatorFees[_originator].accrue();\n\n        if (accrued > 0) {\n            totalOriginatorFeeMinted += accrued;\n            originatorFeeMinted[_originator] += accrued;\n            musd.mint(_originator, accrued);\n            emit OriginatorFeeAccrued(\n                _originator,\n                accrued,\n                totalOriginatorFeeMinted\n            );\n        }\n    }\n\n    /// @dev Snapshot the combined-fee accumulator so that its pending amount\n    ///      is captured in totalFeesStored before the numerator changes.\n    function _snapshotCombinedFees() internal {\n        totalFeesStored += combinedFees.accrue();\n    }\n}\n","deployed_bytecode":"0x608060405234801561000f575f5ffd5b5060043610610304575f3560e01c80638456cb5911610198578063d63f185f116100eb578063ec6a0e5e1161009a578063ec6a0e5e14610717578063ec83fd0314610737578063ece1d6e51461074a578063ef873c0a1461076c578063f2c992a414610774578063f36c8f5c14610788578063feee0d9d1461079c578063ff76f310146107af575f5ffd5b8063d63f185f14610659578063db87b1ff1461066c578063e487893f14610674578063e5dd6c5c14610687578063e63ab1e914610691578063e871a223146106a5578063eae3b917146106e4575f5ffd5b8063a6afed9511610147578063a6afed95146105d6578063b89ad25f146105de578063c0c4a6d414610605578063c392f7661461060f578063ca15c8731461061f578063cab666d014610632578063d547741f14610646575f5ffd5b80638456cb59146105565780639010d07c1461055e57806391d148541461057157806392878eb9146105845780639c0b920814610597578063a217fddf146105bc578063a2fdbcef146105c3575f5ffd5b806336568abe1161025b57806359d31fb31161020a57806359d31fb3146104d75780635b75bba3146104ea5780635c975abb146104fd5780636a23f0b414610508578063741bef1a1461051257806375719a8c1461052657806376c71ca114610539578063782019c414610543575f5ffd5b806336568abe146104585780633f4ba83a1461046b5780634070a0c9146104735780634597f6ed146104865780634b1533b2146104b25780634b68f8a1146104bc578063564afa3a146104cf575f5ffd5b806320d56caa116102b757806320d56caa146103b257806323c8521b146103d2578063248a9ca3146103e5578063262ab1f8146104075780632ba065dd146104115780632f2ff15d146104315780633174df7e14610444575f5ffd5b8062f989ad1461030857806301ffc9a71461031d57806306d6da2e146103455780630f93be011461035d57806312bf2ba11461036c5780631322e56e1461037f5780631928b3cb14610392575b5f5ffd5b61031b6103163660046137b2565b6107b9565b005b61033061032b3660046137d2565b610880565b60405190151581526020015b60405180910390f35b61034f61013b5481565b60405190815260200161033c565b61034f670f43fc2c04ee000081565b61031b61037a366004613840565b6108aa565b61031b61038d3660046137b2565b610b44565b6103a56103a0366004613887565b610dcd565b60405161033c919061390c565b61034f6103c0366004613887565b5f908152610132602052604090205490565b61031b6103e03660046139f4565b610f75565b61034f6103f3366004613887565b5f9081526065602052604090206001015490565b61034f61013e5481565b61042461041f366004613887565b611114565b60405161033c9190613a1d565b61031b61043f366004613a73565b611177565b61034f5f5160206140dd5f395f51905f5281565b61031b610466366004613a73565b6111a0565b61031b61121e565b61031b610481366004613887565b611240565b6101305461049a906001600160a01b031681565b6040516001600160a01b03909116815260200161033c565b61034f6101335481565b61034f6104ca366004613887565b611295565b61034f611392565b61031b6104e5366004613840565b6113a3565b61031b6104f8366004613aa1565b61162f565b60fb5460ff16610330565b61034f61013f5481565b61012f5461049a906001600160a01b031681565b61031b610534366004613ad2565b611640565b61034f6101415481565b61034f610551366004613aa1565b6119f9565b61031b611a1a565b61049a61056c3660046137b2565b611a39565b61033061057f366004613a73565b611a57565b61034f610592366004613887565b611a81565b61013c5461013d546105a7919082565b6040805192835260208301919091520161033c565b61034f5f81565b61034f6105d1366004613887565b611b55565b61031b611c19565b6105a76105ec366004613aa1565b6101386020525f90815260409020805460019091015482565b61034f6101375481565b61013554610136546105a7919082565b61034f61062d366004613887565b611c2b565b61012d5461049a906001600160a01b031681565b61031b610654366004613a73565b611c41565b61031b610667366004613b9e565b611c65565b61034f611cc1565b61031b610682366004613bb7565b611d15565b61034f6101395481565b61034f5f5160206140bd5f395f51905f5281565b6106b86106b3366004613887565b61233c565b60408051958652602086019490945292840191909152151560608301521515608082015260a00161033c565b6106f76106f2366004613887565b61237c565b60408051948552602085019390935291830152606082015260800161033c565b61034f610725366004613aa1565b61013a6020525f908152604090205481565b61031b610745366004613c60565b6123e1565b610140546107599061ffff1681565b60405161ffff909116815260200161033c565b61034f601481565b61012e5461049a906001600160a01b031681565b61034f5f51602061409d5f395f51905f5281565b61031b6107aa366004613c60565b61258e565b61034f6101345481565b816107d05f5160206140dd5f395f51905f52612741565b5f8181526101316020526040902060016009820154600160a01b900460ff1660038111156108005761080061389e565b1461082657604051637196abbf60e01b8152600481018390526024015b60405180910390fd5b60078101546001600160a01b0316331461085657604051631294b1c360e11b81526004810183905260240161081d565b61085e61274b565b610866612791565b61087084846127ea565b61087a600160c955565b50505050565b5f6001600160e01b03198216635a05180f60e01b14806108a457506108a482612aac565b92915050565b826108c15f5160206140dd5f395f51905f52612741565b5f8181526101316020526040902060016009820154600160a01b900460ff1660038111156108f1576108f161389e565b1461091257604051637196abbf60e01b81526004810183905260240161081d565b60078101546001600160a01b0316331461094257604051631294b1c360e11b81526004810183905260240161081d565b61094a61274b565b610952612791565b5f839003610973576040516335cc39d360e21b815260040160405180910390fd5b5f85815261013160205260409020600a810154601490610994908690613c9e565b11156109c657600a8101546109aa908590613c9e565b604051638a5b4f9960e01b815260040161081d91815260200190565b5f5b84811015610af2575f8686838181106109e3576109e3613cb1565b61012e546040516331a9108f60e11b8152602092909202939093013560048201819052935033926001600160a01b03169150636352211e90602401602060405180830381865afa158015610a39573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a5d9190613cc5565b6001600160a01b031614610a8757604051630e35d34560e11b81526004810182905260240161081d565b5f81815261013260205260409020548015610abf5760405163f9fa5d9560e01b8152600481018390526024810182905260440161081d565b505f8181526101326020908152604082208a9055600a8501805460018181018355918452919092200191909155016109c8565b50857f4847e7e5826ec6214e03626d14dec2d43abd228be3af7578f3a18a65039b1992868684600a01604051610b2a93929190613d10565b60405180910390a250610b3d600160c955565b5050505050565b81610b5b5f5160206140dd5f395f51905f52612741565b5f8181526101316020526040902060016009820154600160a01b900460ff166003811115610b8b57610b8b61389e565b14610bac57604051637196abbf60e01b81526004810183905260240161081d565b60078101546001600160a01b03163314610bdc57604051631294b1c360e11b81526004810183905260240161081d565b610be461274b565b610bec612791565b825f03610c0c57604051631f2a200560e01b815260040160405180910390fd5b5f848152610131602052604090206101415461013354610c2d908690613c9e565b1115610c68578361013354610c429190613c9e565b61014154604051637c2e2b2b60e11b81526004810192909252602482015260440161081d565b6009810154610c7f906001600160a01b0316612ae0565b610c8881612af9565b505083815f015f828254610c9c9190613c9e565b909155505060098101546004820154610cd09186916001600160a01b039091169061ffff8082169162010000900416612b72565b5f610cda86611b55565b90508160060154811015610d1857600682015460405163a6a6101b60e01b81526004810188905260248101839052604481019190915260640161081d565b61012d5460088301546040516340c10f1960e01b81526001600160a01b03928316926340c10f1992610d51929116908990600401613d6d565b5f604051808303815f87803b158015610d68575f5ffd5b505af1158015610d7a573d5f5f3e3d5ffd5b505083546040518993507f2118334e388b7134a6f90e5aaf39ebfd7b72debb8d1c454fbe09d4156482c4759250610db991898252602082015260400190565b60405180910390a2505061087a600160c955565b610e3b604080516101a0810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052906101608201908152602001606081525090565b5f828152610131602090815260409182902082516101a081018452815481526001820154928101929092526002810154928201929092526003808301546060830152600483015461ffff8082166080850152620100009091041660a0830152600583015460c0830152600683015460e083015260078301546001600160a01b03908116610100840152600884015481166101208401526009840154908116610140840152919291610160840191600160a01b90910460ff1690811115610f0357610f0361389e565b6003811115610f1457610f1461389e565b8152602001600a8201805480602002602001604051908101604052809291908181526020018280548015610f6557602002820191905f5260205f20905b815481526020019060010190808311610f51575b5050505050815250509050919050565b82610f8c5f5160206140dd5f395f51905f52612741565b5f8181526101316020526040902060016009820154600160a01b900460ff166003811115610fbc57610fbc61389e565b14610fdd57604051637196abbf60e01b81526004810183905260240161081d565b60078101546001600160a01b0316331461100d57604051631294b1c360e11b81526004810183905260240161081d565b61101561274b565b61101d612791565b670f43fc2c04ee00008310156110495760405163802c845d60e01b81526004810184905260240161081d565b8284116110735760405163a542244560e01b8152600481018590526024810184905260440161081d565b5f8581526101316020526040812060058101869055600681018590559061109987611b55565b9050848110156110cd5760405163a6a6101b60e01b815260048101889052602481018290526044810186905260640161081d565b604080518781526020810187905288917f82d06806d4681116daeab26dba8123da5d052b917f2b6e6d7a2de1c09df3ba51910160405180910390a25050610b3d600160c955565b5f8181526101316020908152604091829020600a0180548351818402810184019094528084526060939283018282801561116b57602002820191905f5260205f20905b815481526020019060010190808311611157575b50505050509050919050565b5f8281526065602052604090206001015461119181612741565b61119b8383612bed565b505050565b6001600160a01b03811633146112105760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b606482015260840161081d565b61121a8282612c0e565b5050565b5f51602061409d5f395f51905f5261123581612741565b61123d612c2f565b50565b5f51602061409d5f395f51905f5261125781612741565b6101418290556040518281527fcda03296b648d791f2cee5a5af4b32860d8a3d01fae4126b12b4081224003767906020015b60405180910390a15050565b5f816112ad5f5160206140dd5f395f51905f52612741565b5f8181526101316020526040902060016009820154600160a01b900460ff1660038111156112dd576112dd61389e565b146112fe57604051637196abbf60e01b81526004810183905260240161081d565b60078101546001600160a01b0316331461132e57604051631294b1c360e11b81526004810183905260240161081d565b61133661274b565b61133e612791565b5f8481526101316020526040902061135581612c81565b61135e82612c9a565b825461136a9190613c9e565b6113749190613c9e565b935061138085856127ea565b5061138b600160c955565b5050919050565b5f61139e610135612cb3565b905090565b826113ba5f5160206140dd5f395f51905f52612741565b5f8181526101316020526040902060016009820154600160a01b900460ff1660038111156113ea576113ea61389e565b1461140b57604051637196abbf60e01b81526004810183905260240161081d565b60078101546001600160a01b0316331461143b57604051631294b1c360e11b81526004810183905260240161081d565b61144361274b565b61144b612791565b5f83900361146c576040516335cc39d360e21b815260040160405180910390fd5b5f8581526101316020526040812090600a8201905b8581101561159a575f87878381811061149c5761149c613cb1565b905060200201359050886101325f8381526020019081526020015f2054146114e15760405163b0c13c9f60e01b815260048101829052602481018a905260440161081d565b82545f5b81811015611581578285828154811061150057611500613cb1565b905f5260205f20015403611579578461151a600184613d86565b8154811061152a5761152a613cb1565b905f5260205f20015485828154811061154557611545613cb1565b905f5260205f2001819055508480548061156157611561613d99565b600190038181905f5260205f20015f90559055611581565b6001016114e5565b50505f9081526101326020526040812055600101611481565b505f6115a588611b55565b905082600601548110156115e357600683015460405163a6a6101b60e01b8152600481018a905260248101839052604481019190915260640161081d565b877f02403dfe11b4461cb23bc722e800e5bad3ef47f2b1bd6bad6a40289132fd185d888886600a0160405161161a93929190613d10565b60405180910390a2505050610b3d600160c955565b61163761274b565b61123d81612cd6565b5f54610100900460ff161580801561165e57505f54600160ff909116105b806116775750303b15801561167757505f5460ff166001145b6116da5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161081d565b5f805460ff1916600117905580156116fb575f805461ff0019166101001790555b6001600160a01b038b166117225760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b038a166117495760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b0389166117705760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b0388166117975760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b0387166117be5760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b0386166117e55760405163d92e233d60e01b815260040160405180910390fd5b6117ed612df6565b6117f5612e1c565b6117fd612e4a565b61012d80546001600160a01b03808e166001600160a01b03199283161790925561012e80548d841690831617905561012f80548c84169083161790556101308054928916929091169190911790554261013681905561013d556118605f89612bed565b6118775f51602061409d5f395f51905f5289612bed565b61188e5f5160206140bd5f395f51905f5288612bed565b6118b25f5160206140dd5f395f51905f525f51602061409d5f395f51905f52612e78565b6118d65f5160206140bd5f395f51905f525f51602061409d5f395f51905f52612e78565b5f5b848110156119255761191d5f5160206140dd5f395f51905f5287878481811061190357611903613cb1565b90506020020160208101906119189190613aa1565b612bed565b6001016118d8565b50610140805461ffff191661ffff85169081179091556101418390556040519081527f428d0ce3ec19d535d61922be4f747f68df18c0a0411da1190470f0441d24024c9060200160405180910390a16040518281527fcda03296b648d791f2cee5a5af4b32860d8a3d01fae4126b12b40812240037679060200160405180910390a180156119ec575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050505050505050565b6001600160a01b0381165f908152610138602052604081206108a490612cb3565b5f5160206140bd5f395f51905f52611a3181612741565b61123d612ec2565b5f828152609760205260408120611a509083612eff565b9392505050565b5f9182526065602090815260408084206001600160a01b0393909316845291905290205460ff1690565b5f81815261013160205260408120600a0181805b8254811015611b4d5761012e548354611b39916001600160a01b03169063b45a3c0e90869085908110611aca57611aca613cb1565b905f5260205f2001546040518263ffffffff1660e01b8152600401611af191815260200190565b608060405180830381865afa158015611b0c573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b309190613dd0565b51600f0b612f0a565b611b439083613c9e565b9150600101611a95565b509392505050565b5f5f611b6083611a81565b90505f61012f5f9054906101000a90046001600160a01b03166001600160a01b0316630fdb11cf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611bb4573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611bd89190613e48565b90505f611be48561237c565b9350505050805f03611bfb57505f19949350505050565b80611c068385613e5f565b611c109190613e76565b95945050505050565b611c2161274b565b611c29612f35565b565b5f8181526097602052604081206108a49061300d565b5f82815260656020526040902060010154611c5b81612741565b61119b8383612c0e565b5f51602061409d5f395f51905f52611c7c81612741565b610140805461ffff191661ffff84169081179091556040519081527f428d0ce3ec19d535d61922be4f747f68df18c0a0411da1190470f0441d24024c90602001611289565b5f5f611cce61013c612cb3565b61013e54611cdc9190613c9e565b90505f61013f548211611cef575f611cfd565b61013f54611cfd9083613d86565b90508061013354611d0e9190613c9e565b9250505090565b5f5160206140dd5f395f51905f52611d2c81612741565b611d3461274b565b611d3c612791565b611d4589612ae0565b8a611d635760405163cf17af3760e01b815260040160405180910390fd5b6001600160a01b038a16611d8a5760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b038916611db15760405163d92e233d60e01b815260040160405180910390fd5b875f03611dd157604051631f2a200560e01b815260040160405180910390fd5b5f5f8c81526101316020526040902060090154600160a01b900460ff166003811115611dff57611dff61389e565b14611e205760405163f13a34ab60e01b8152600481018c905260240161081d565b5f849003611e41576040516335cc39d360e21b815260040160405180910390fd5b6014841115611e6657604051638a5b4f9960e01b81526004810185905260240161081d565b5f611e7861ffff808916908a16613e95565b6101405490915061ffff1663ffffffff82161115611ec057610140546040516308371bf960e11b815263ffffffff8316600482015261ffff909116602482015260440161081d565b50610141548861013354611ed49190613c9e565b1115611ee9578761013354610c429190613c9e565b670f43fc2c04ee0000821015611f155760405163802c845d60e01b81526004810183905260240161081d565b818311611f3f5760405163a542244560e01b8152600481018490526024810183905260440161081d565b5f5b84811015612052575f868683818110611f5c57611f5c613cb1565b61012e546040516331a9108f60e11b8152602092909202939093013560048201819052935033926001600160a01b03169150636352211e90602401602060405180830381865afa158015611fb2573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611fd69190613cc5565b6001600160a01b03161461200057604051630e35d34560e11b81526004810182905260240161081d565b5f818152610132602052604090205480156120385760405163f9fa5d9560e01b8152600481018390526024810182905260440161081d565b505f908152610132602052604090208c9055600101611f41565b50604051806101a001604052808981526020015f81526020015f81526020014281526020018861ffff1681526020018761ffff168152602001848152602001838152602001336001600160a01b031681526020018b6001600160a01b031681526020018a6001600160a01b03168152602001600160038111156120d7576120d761389e565b81526020018686808060200260200160405190810160405280939291908181526020018383602002808284375f9201829052509390945250508d81526101316020908152604091829020845181559084015160018201559083015160028201556060830151600380830191909155608084015160048301805460a087015161ffff908116620100000263ffffffff1990921693169290921791909117905560c0840151600583015560e084015160068301556101008401516007830180546001600160a01b039283166001600160a01b031991821617909155610120860151600885018054918416918316919091179055610140860151600985018054919093169181168217835561016087015194955091926001600160a81b03199092161790600160a01b90849081111561220f5761220f61389e565b0217905550610180820151600a8201906122299082613eb1565b509050505f6122378c611b55565b90508281101561226b5760405163a6a6101b60e01b8152600481018d9052602481018290526044810184905260640161081d565b50612278888a8989612b72565b61012d546040516340c10f1960e01b81526001600160a01b03909116906340c10f19906122ab908d908c90600401613d6d565b5f604051808303815f87803b1580156122c2575f5ffd5b505af11580156122d4573d5f5f3e3d5ffd5b50505050896001600160a01b0316336001600160a01b03168c7f71b8cfcb91be8c2c8670be096e68d6366139b0e2d777e4f77ade632a4d7211968b8d8c8c8a8a8e8e60405161232a989796959493929190613f4c565b60405180910390a46119ec600160c955565b5f81815261013160205260408120819081908190819061235b87611b55565b60058201546006909201549098919750955086881094508588109350915050565b5f8181526101316020526040812080549190819081908482036123ab575f5f5f5f9450945094509450506123da565b6123b481612c9a565b93506123bf81612c81565b9250826123cc8587613c9e565b6123d69190613c9e565b9150505b9193509193565b5f5160206140dd5f395f51905f526123f881612741565b61240061274b565b612408612791565b5f8381526101316020526040902060016009820154600160a01b900460ff1660038111156124385761243861389e565b1461245957604051637196abbf60e01b81526004810185905260240161081d565b60078101546001600160a01b0316331461248957604051631294b1c360e11b81526004810185905260240161081d565b60048101545f906124a89061ffff620100009091048116908616613e95565b6101405490915061ffff1663ffffffff821611156124f057610140546040516308371bf960e11b815263ffffffff8316600482015261ffff909116602482015260440161081d565b6009820154612507906001600160a01b0316612ae0565b61251082612af9565b50506004820154825461ffff9091169061252b908287613016565b60048301805461ffff191661ffff878116918217909255604080519284168352602083019190915287917fb393a3069b786b6a3b69171c7aa4df70b1d23b71a3ffde7e19e398e1c49a326491015b60405180910390a250505061119b600160c955565b5f5160206140dd5f395f51905f526125a581612741565b6125ad61274b565b6125b5612791565b5f8381526101316020526040902060016009820154600160a01b900460ff1660038111156125e5576125e561389e565b1461260657604051637196abbf60e01b81526004810185905260240161081d565b60078101546001600160a01b0316331461263657604051631294b1c360e11b81526004810185905260240161081d565b60048101545f9061264e9061ffff8087169116613e95565b6101405490915061ffff1663ffffffff8216111561269657610140546040516308371bf960e11b815263ffffffff8316600482015261ffff909116602482015260440161081d565b60098201546126ad906001600160a01b0316612ae0565b6126b682612af9565b50506004820154825460098401546201000090920461ffff16916126e591906001600160a01b0316838861304a565b60048301805463ffff000019166201000061ffff88811691820292909217909255604080519184168252602082019290925287917f79ceb5b348d77f792cf231e2cc96b3eb0ee412c2fe149d7a3f39b4b9810b11f39101612579565b61123d813361309d565b60fb5460ff1615611c295760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015260640161081d565b600260c954036127e35760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161081d565b600260c955565b805f0361280a57604051631f2a200560e01b815260040160405180910390fd5b5f82815261013160205260409020600981015461282f906001600160a01b0316612ae0565b5f61283982612c81565b61284283612c9a565b61284c9190613c9e565b5f60018401819055600284015542600384015590508061013f5f8282546128739190613c9e565b9091555050808310156128aa57604051633f4c8ac360e11b815260048101859052602481018490526044810182905260640161081d565b5f6128b58285613d86565b83549091508111156128ee5782546040516352da3e7360e01b81526004810187905260248101839052604481019190915260640161081d565b61012d54604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac906129219033908890600401613d6d565b5f604051808303815f87803b158015612938575f5ffd5b505af115801561294a573d5f5f3e3d5ffd5b5050505080835f015f8282546129609190613d86565b9091555050600983015460048401546129949183916001600160a01b039091169061ffff80821691620100009004166130f6565b82545f03612a0a5760098301805460ff60a01b1916600160a11b179055600a83015f5b81548110156129fa576101325f8383815481106129d6576129d6613cb1565b905f5260205f20015481526020019081526020015f205f90558060010190506129b7565b50612a08600a85015f613783565b505b825460405186917f868c03be9ffd10b7bd6294b60684c640d935b4f31deaf6662984e7de7da0708791612a4591888252602082015260400190565b60405180910390a260026009840154600160a01b900460ff166003811115612a6f57612a6f61389e565b03610b3d5760405185907fb77a99aa6bf8135a033a72ab89373f6f8977dc081d277755b7622c1782a14799905f90a25050505050565b600160c955565b5f6001600160e01b03198216637965db0b60e01b14806108a457506301ffc9a760e01b6001600160e01b03198316146108a4565b612ae8612f35565b612af181612cd6565b61123d613171565b60048101545f908190612b1290849061ffff1642613194565b9150612b31838460040160029054906101000a900461ffff1642613194565b905081836001015f828254612b469190613c9e565b9250508190555080836002015f828254612b609190613c9e565b90915550504260039093019290925591565b836101335f828254612b849190613c9e565b92505081905550836101345f828254612b9d9190613c9e565b90915550612bb090506101358584613212565b6001600160a01b0383165f90815261013860205260409020612bd3908583613212565b612be061013c8584613212565b61087a61013c8583613212565b612bf7828261323b565b5f82815260976020526040902061119b90826132c0565b612c1882826132d4565b5f82815260976020526040902061119b908261333a565b612c3761334e565b60fb805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b5f612c8b82613397565b82600201546108a49190613c9e565b5f612ca4826133b5565b82600101546108a49190613c9e565b80545f908103612cc457505f919050565b6108a4825f01548360010154426133cc565b6001600160a01b0381165f90815261013860205260408120612cf7906133f4565b9050801561121a57806101395f828254612d119190613c9e565b90915550506001600160a01b0382165f90815261013a602052604081208054839290612d3e908490613c9e565b909155505061012d546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990612d769085908590600401613d6d565b5f604051808303815f87803b158015612d8d575f5ffd5b505af1158015612d9f573d5f5f3e3d5ffd5b50505050816001600160a01b03167fa71a962c32d0b62575a9e57e1e64b9ee472f6a58755529ed4606f5deca62a52f8261013954604051612dea929190918252602082015260400190565b60405180910390a25050565b5f54610100900460ff16611c295760405162461bcd60e51b815260040161081d90613fa1565b5f54610100900460ff16612e425760405162461bcd60e51b815260040161081d90613fa1565b611c29613410565b5f54610100900460ff16612e705760405162461bcd60e51b815260040161081d90613fa1565b611c29613436565b5f82815260656020526040808220600101805490849055905190918391839186917fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff9190a4505050565b612eca61274b565b60fb805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258612c643390565b5f611a508383613468565b5f5f82600f0b1215612f2e5760405162406f5d60e21b815260040160405180910390fd5b50600f0b90565b5f612f416101356133f4565b9050801561123d57806101375f828254612f5b9190613c9e565b909155505061012d54610130546040516340c10f1960e01b81526001600160a01b03928316926340c10f1992612f98929116908590600401613d6d565b5f604051808303815f87803b158015612faf575f5ffd5b505af1158015612fc1573d5f5f3e3d5ffd5b505050507f3d8708181c6452c5711a2b4c6ed3f12149f6ea35f78549aba00a89d041e766ca8161013754604051613002929190918252602082015260400190565b60405180910390a150565b5f6108a4825490565b613023610135848461348e565b6130306101358483613212565b61303d61013c848461348e565b61119b61013c8483613212565b6001600160a01b0383165f9081526101386020526040902061306d90858461348e565b6001600160a01b0383165f90815261013860205260409020613090908583613212565b612be061013c858461348e565b6130a78282611a57565b61121a576130b4816134ad565b6130bf8360206134bf565b6040516020016130d0929190614003565b60408051601f198184030181529082905262461bcd60e51b825261081d91600401614052565b836101335f8282546131089190613d86565b925050819055508361013b5f8282546131219190613c9e565b909155506131349050610135858461348e565b6001600160a01b0383165f9081526101386020526040902061315790858361348e565b61316461013c858461348e565b61087a61013c858361348e565b61317c61013c6133f4565b61013e5f82825461318d9190613c9e565b9091555050565b825460038401545f91908115806131ad575061ffff8516155b806131b85750808411155b156131c7575f92505050611a50565b5f6131d28286613d86565b90506131e46301e18558612710613e5f565b61ffff87166131f38584613e5f565b6131fd9190613e5f565b6132079190613e76565b979650505050505050565b6132208261ffff8316613e5f565b835f015f8282546132319190613c9e565b9091555050505050565b6132458282611a57565b61121a575f8281526065602090815260408083206001600160a01b03851684529091529020805460ff1916600117905561327c3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b5f611a50836001600160a01b038416613654565b6132de8282611a57565b1561121a575f8281526065602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b5f611a50836001600160a01b0384166136a0565b60fb5460ff16611c295760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015260640161081d565b5f6108a4828360040160029054906101000a900461ffff1642613194565b60048101545f906108a490839061ffff1642613194565b5f806133d88484613d86565b90506133ea6301e18558612710613e5f565b611c068683613e5f565b5f5f6133ff83612cb3565b426001909401939093555090919050565b5f54610100900460ff16612aa55760405162461bcd60e51b815260040161081d90613fa1565b5f54610100900460ff1661345c5760405162461bcd60e51b815260040161081d90613fa1565b60fb805460ff19169055565b5f825f01828154811061347d5761347d613cb1565b905f5260205f200154905092915050565b61349c8261ffff8316613e5f565b835f015f8282546132319190613d86565b60606108a46001600160a01b03831660145b60605f6134cd836002613e5f565b6134d8906002613c9e565b6001600160401b038111156134ef576134ef613dad565b6040519080825280601f01601f191660200182016040528015613519576020820181803683370190505b509050600360fc1b815f8151811061353357613533613cb1565b60200101906001600160f81b03191690815f1a905350600f60fb1b8160018151811061356157613561613cb1565b60200101906001600160f81b03191690815f1a9053505f613583846002613e5f565b61358e906001613c9e565b90505b6001811115613605576f181899199a1a9b1b9c1cb0b131b232b360811b85600f16601081106135c2576135c2613cb1565b1a60f81b8282815181106135d8576135d8613cb1565b60200101906001600160f81b03191690815f1a90535060049490941c936135fe81614087565b9050613591565b508315611a505760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e74604482015260640161081d565b5f81815260018301602052604081205461369957508154600181810184555f8481526020808220909301849055845484825282860190935260409020919091556108a4565b505f6108a4565b5f818152600183016020526040812054801561377a575f6136c2600183613d86565b85549091505f906136d590600190613d86565b9050818114613734575f865f0182815481106136f3576136f3613cb1565b905f5260205f200154905080875f01848154811061371357613713613cb1565b5f918252602080832090910192909255918252600188019052604090208390555b855486908061374557613745613d99565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f9055600193505050506108a4565b5f9150506108a4565b5080545f8255905f5260205f209061123d91905f5b808211156137ad575f81840155600101613798565b505090565b5f5f604083850312156137c3575f5ffd5b50508035926020909101359150565b5f602082840312156137e2575f5ffd5b81356001600160e01b031981168114611a50575f5ffd5b5f5f83601f840112613809575f5ffd5b5081356001600160401b0381111561381f575f5ffd5b6020830191508360208260051b8501011115613839575f5ffd5b9250929050565b5f5f5f60408486031215613852575f5ffd5b8335925060208401356001600160401b0381111561386e575f5ffd5b61387a868287016137f9565b9497909650939450505050565b5f60208284031215613897575f5ffd5b5035919050565b634e487b7160e01b5f52602160045260245ffd5b600481106138ce57634e487b7160e01b5f52602160045260245ffd5b9052565b5f8151808452602084019350602083015f5b828110156139025781518652602095860195909101906001016138e4565b5093949350505050565b60208152815160208201526020820151604082015260408201516060820152606082015160808201525f608083015161394b60a084018261ffff169052565b5060a083015161ffff811660c08401525060c083015160e083015260e083015161010083015261010083015161398d6101208401826001600160a01b03169052565b506101208301516001600160a01b038116610140840152506101408301516001600160a01b038116610160840152506101608301516139d06101808401826138b2565b506101808301516101a0808401526139ec6101c08401826138d2565b949350505050565b5f5f5f60608486031215613a06575f5ffd5b505081359360208301359350604090920135919050565b602080825282518282018190525f918401906040840190835b81811015613a54578351835260209384019390920191600101613a36565b509095945050505050565b6001600160a01b038116811461123d575f5ffd5b5f5f60408385031215613a84575f5ffd5b823591506020830135613a9681613a5f565b809150509250929050565b5f60208284031215613ab1575f5ffd5b8135611a5081613a5f565b803561ffff81168114613acd575f5ffd5b919050565b5f5f5f5f5f5f5f5f5f5f6101208b8d031215613aec575f5ffd5b8a35613af781613a5f565b995060208b0135613b0781613a5f565b985060408b0135613b1781613a5f565b975060608b0135613b2781613a5f565b965060808b0135613b3781613a5f565b955060a08b0135613b4781613a5f565b945060c08b01356001600160401b03811115613b61575f5ffd5b613b6d8d828e016137f9565b9095509350613b80905060e08c01613abc565b91505f6101008c01359050809150509295989b9194979a5092959850565b5f60208284031215613bae575f5ffd5b611a5082613abc565b5f5f5f5f5f5f5f5f5f5f6101208b8d031215613bd1575f5ffd5b8a35995060208b0135613be381613a5f565b985060408b0135613bf381613a5f565b975060608b01359650613c0860808c01613abc565b9550613c1660a08c01613abc565b945060c08b01356001600160401b03811115613c30575f5ffd5b613c3c8d828e016137f9565b9b9e9a9d50989b979a969995989760e0810135966101009091013595509350505050565b5f5f60408385031215613c71575f5ffd5b82359150613c8160208401613abc565b90509250929050565b634e487b7160e01b5f52601160045260245ffd5b808201808211156108a4576108a4613c8a565b634e487b7160e01b5f52603260045260245ffd5b5f60208284031215613cd5575f5ffd5b8151611a5081613a5f565b8183525f6001600160fb1b03831115613cf7575f5ffd5b8260051b80836020870137939093016020019392505050565b604081525f613d23604083018587613ce0565b8281036020840152808454808352602083019150855f5260205f2092505f5b81811015613d60578354835260019384019360209093019201613d42565b5090979650505050505050565b6001600160a01b03929092168252602082015260400190565b818103818111156108a4576108a4613c8a565b634e487b7160e01b5f52603160045260245ffd5b634e487b7160e01b5f52604160045260245ffd5b80518015158114613acd575f5ffd5b5f6080828403128015613de1575f5ffd5b50604051608081016001600160401b0381118282101715613e0457613e04613dad565b6040528251600f81900b8114613e18575f5ffd5b815260208381015190820152613e3060408401613dc1565b60408201526060928301519281019290925250919050565b5f60208284031215613e58575f5ffd5b5051919050565b80820281158282048414176108a4576108a4613c8a565b5f82613e9057634e487b7160e01b5f52601260045260245ffd5b500490565b63ffffffff81811683821601908111156108a4576108a4613c8a565b81516001600160401b03811115613eca57613eca613dad565b600160401b811115613ede57613ede613dad565b815481835580821015613f1257825f528160205f20018282035f5b81811015613f0e575f83820155600101613ef9565b5050505b5060208301613f26835f9081526020902090565b5f5b83811015613f4457825182820155602090920191600101613f28565b505050505050565b88815260018060a01b038816602082015261ffff8716604082015261ffff861660608201528460808201528360a082015260e060c08201525f613f9360e083018486613ce0565b9a9950505050505050505050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b5f81518060208401855e5f93019283525090919050565b76020b1b1b2b9b9a1b7b73a3937b61d1030b1b1b7bab73a1604d1b81525f61402e6017830185613fec565b7001034b99036b4b9b9b4b733903937b6329607d1b8152611c106011820185613fec565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b5f8161409557614095613c8a565b505f19019056fe71840dc4906352362b0cdaf79870196c8e42acafade72d5d5a6d59291253ceb165d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862ae99d769f717ef5998d23b311cb6df42c9f772c997399f5192f2452542a0d8ca0a2646970667358221220a064fecc57b9daea8677cadef7b9380b32443c637ed4ba2cc82956b1492e2a2864736f6c63430008210033","optimization_enabled":true,"verified_twin_address_hash":null,"is_verified":true,"compiler_settings":{"evmVersion":"osaka","libraries":{},"metadata":{"useLiteralContent":true},"optimizer":{"enabled":true,"runs":100},"outputSelection":{"*":{"":["*"],"*":["*"]}}},"optimization_runs":100,"sourcify_repo_url":null,"decoded_constructor_args":null,"has_methods_write":true,"compiler_version":"v0.8.33+commit.64118f21","is_verified_via_verifier_alliance":false,"verified_at":"2026-06-29T07:53:54.644301Z","implementations":[],"proxy_type":null,"external_libraries":[],"creation_bytecode":"0x6080604052348015600e575f5ffd5b5060156019565b60d3565b5f54610100900460ff161560835760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b5f5460ff9081161460d1575f805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b614132806100e05f395ff3fe608060405234801561000f575f5ffd5b5060043610610304575f3560e01c80638456cb5911610198578063d63f185f116100eb578063ec6a0e5e1161009a578063ec6a0e5e14610717578063ec83fd0314610737578063ece1d6e51461074a578063ef873c0a1461076c578063f2c992a414610774578063f36c8f5c14610788578063feee0d9d1461079c578063ff76f310146107af575f5ffd5b8063d63f185f14610659578063db87b1ff1461066c578063e487893f14610674578063e5dd6c5c14610687578063e63ab1e914610691578063e871a223146106a5578063eae3b917146106e4575f5ffd5b8063a6afed9511610147578063a6afed95146105d6578063b89ad25f146105de578063c0c4a6d414610605578063c392f7661461060f578063ca15c8731461061f578063cab666d014610632578063d547741f14610646575f5ffd5b80638456cb59146105565780639010d07c1461055e57806391d148541461057157806392878eb9146105845780639c0b920814610597578063a217fddf146105bc578063a2fdbcef146105c3575f5ffd5b806336568abe1161025b57806359d31fb31161020a57806359d31fb3146104d75780635b75bba3146104ea5780635c975abb146104fd5780636a23f0b414610508578063741bef1a1461051257806375719a8c1461052657806376c71ca114610539578063782019c414610543575f5ffd5b806336568abe146104585780633f4ba83a1461046b5780634070a0c9146104735780634597f6ed146104865780634b1533b2146104b25780634b68f8a1146104bc578063564afa3a146104cf575f5ffd5b806320d56caa116102b757806320d56caa146103b257806323c8521b146103d2578063248a9ca3146103e5578063262ab1f8146104075780632ba065dd146104115780632f2ff15d146104315780633174df7e14610444575f5ffd5b8062f989ad1461030857806301ffc9a71461031d57806306d6da2e146103455780630f93be011461035d57806312bf2ba11461036c5780631322e56e1461037f5780631928b3cb14610392575b5f5ffd5b61031b6103163660046137b2565b6107b9565b005b61033061032b3660046137d2565b610880565b60405190151581526020015b60405180910390f35b61034f61013b5481565b60405190815260200161033c565b61034f670f43fc2c04ee000081565b61031b61037a366004613840565b6108aa565b61031b61038d3660046137b2565b610b44565b6103a56103a0366004613887565b610dcd565b60405161033c919061390c565b61034f6103c0366004613887565b5f908152610132602052604090205490565b61031b6103e03660046139f4565b610f75565b61034f6103f3366004613887565b5f9081526065602052604090206001015490565b61034f61013e5481565b61042461041f366004613887565b611114565b60405161033c9190613a1d565b61031b61043f366004613a73565b611177565b61034f5f5160206140dd5f395f51905f5281565b61031b610466366004613a73565b6111a0565b61031b61121e565b61031b610481366004613887565b611240565b6101305461049a906001600160a01b031681565b6040516001600160a01b03909116815260200161033c565b61034f6101335481565b61034f6104ca366004613887565b611295565b61034f611392565b61031b6104e5366004613840565b6113a3565b61031b6104f8366004613aa1565b61162f565b60fb5460ff16610330565b61034f61013f5481565b61012f5461049a906001600160a01b031681565b61031b610534366004613ad2565b611640565b61034f6101415481565b61034f610551366004613aa1565b6119f9565b61031b611a1a565b61049a61056c3660046137b2565b611a39565b61033061057f366004613a73565b611a57565b61034f610592366004613887565b611a81565b61013c5461013d546105a7919082565b6040805192835260208301919091520161033c565b61034f5f81565b61034f6105d1366004613887565b611b55565b61031b611c19565b6105a76105ec366004613aa1565b6101386020525f90815260409020805460019091015482565b61034f6101375481565b61013554610136546105a7919082565b61034f61062d366004613887565b611c2b565b61012d5461049a906001600160a01b031681565b61031b610654366004613a73565b611c41565b61031b610667366004613b9e565b611c65565b61034f611cc1565b61031b610682366004613bb7565b611d15565b61034f6101395481565b61034f5f5160206140bd5f395f51905f5281565b6106b86106b3366004613887565b61233c565b60408051958652602086019490945292840191909152151560608301521515608082015260a00161033c565b6106f76106f2366004613887565b61237c565b60408051948552602085019390935291830152606082015260800161033c565b61034f610725366004613aa1565b61013a6020525f908152604090205481565b61031b610745366004613c60565b6123e1565b610140546107599061ffff1681565b60405161ffff909116815260200161033c565b61034f601481565b61012e5461049a906001600160a01b031681565b61034f5f51602061409d5f395f51905f5281565b61031b6107aa366004613c60565b61258e565b61034f6101345481565b816107d05f5160206140dd5f395f51905f52612741565b5f8181526101316020526040902060016009820154600160a01b900460ff1660038111156108005761080061389e565b1461082657604051637196abbf60e01b8152600481018390526024015b60405180910390fd5b60078101546001600160a01b0316331461085657604051631294b1c360e11b81526004810183905260240161081d565b61085e61274b565b610866612791565b61087084846127ea565b61087a600160c955565b50505050565b5f6001600160e01b03198216635a05180f60e01b14806108a457506108a482612aac565b92915050565b826108c15f5160206140dd5f395f51905f52612741565b5f8181526101316020526040902060016009820154600160a01b900460ff1660038111156108f1576108f161389e565b1461091257604051637196abbf60e01b81526004810183905260240161081d565b60078101546001600160a01b0316331461094257604051631294b1c360e11b81526004810183905260240161081d565b61094a61274b565b610952612791565b5f839003610973576040516335cc39d360e21b815260040160405180910390fd5b5f85815261013160205260409020600a810154601490610994908690613c9e565b11156109c657600a8101546109aa908590613c9e565b604051638a5b4f9960e01b815260040161081d91815260200190565b5f5b84811015610af2575f8686838181106109e3576109e3613cb1565b61012e546040516331a9108f60e11b8152602092909202939093013560048201819052935033926001600160a01b03169150636352211e90602401602060405180830381865afa158015610a39573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a5d9190613cc5565b6001600160a01b031614610a8757604051630e35d34560e11b81526004810182905260240161081d565b5f81815261013260205260409020548015610abf5760405163f9fa5d9560e01b8152600481018390526024810182905260440161081d565b505f8181526101326020908152604082208a9055600a8501805460018181018355918452919092200191909155016109c8565b50857f4847e7e5826ec6214e03626d14dec2d43abd228be3af7578f3a18a65039b1992868684600a01604051610b2a93929190613d10565b60405180910390a250610b3d600160c955565b5050505050565b81610b5b5f5160206140dd5f395f51905f52612741565b5f8181526101316020526040902060016009820154600160a01b900460ff166003811115610b8b57610b8b61389e565b14610bac57604051637196abbf60e01b81526004810183905260240161081d565b60078101546001600160a01b03163314610bdc57604051631294b1c360e11b81526004810183905260240161081d565b610be461274b565b610bec612791565b825f03610c0c57604051631f2a200560e01b815260040160405180910390fd5b5f848152610131602052604090206101415461013354610c2d908690613c9e565b1115610c68578361013354610c429190613c9e565b61014154604051637c2e2b2b60e11b81526004810192909252602482015260440161081d565b6009810154610c7f906001600160a01b0316612ae0565b610c8881612af9565b505083815f015f828254610c9c9190613c9e565b909155505060098101546004820154610cd09186916001600160a01b039091169061ffff8082169162010000900416612b72565b5f610cda86611b55565b90508160060154811015610d1857600682015460405163a6a6101b60e01b81526004810188905260248101839052604481019190915260640161081d565b61012d5460088301546040516340c10f1960e01b81526001600160a01b03928316926340c10f1992610d51929116908990600401613d6d565b5f604051808303815f87803b158015610d68575f5ffd5b505af1158015610d7a573d5f5f3e3d5ffd5b505083546040518993507f2118334e388b7134a6f90e5aaf39ebfd7b72debb8d1c454fbe09d4156482c4759250610db991898252602082015260400190565b60405180910390a2505061087a600160c955565b610e3b604080516101a0810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052906101608201908152602001606081525090565b5f828152610131602090815260409182902082516101a081018452815481526001820154928101929092526002810154928201929092526003808301546060830152600483015461ffff8082166080850152620100009091041660a0830152600583015460c0830152600683015460e083015260078301546001600160a01b03908116610100840152600884015481166101208401526009840154908116610140840152919291610160840191600160a01b90910460ff1690811115610f0357610f0361389e565b6003811115610f1457610f1461389e565b8152602001600a8201805480602002602001604051908101604052809291908181526020018280548015610f6557602002820191905f5260205f20905b815481526020019060010190808311610f51575b5050505050815250509050919050565b82610f8c5f5160206140dd5f395f51905f52612741565b5f8181526101316020526040902060016009820154600160a01b900460ff166003811115610fbc57610fbc61389e565b14610fdd57604051637196abbf60e01b81526004810183905260240161081d565b60078101546001600160a01b0316331461100d57604051631294b1c360e11b81526004810183905260240161081d565b61101561274b565b61101d612791565b670f43fc2c04ee00008310156110495760405163802c845d60e01b81526004810184905260240161081d565b8284116110735760405163a542244560e01b8152600481018590526024810184905260440161081d565b5f8581526101316020526040812060058101869055600681018590559061109987611b55565b9050848110156110cd5760405163a6a6101b60e01b815260048101889052602481018290526044810186905260640161081d565b604080518781526020810187905288917f82d06806d4681116daeab26dba8123da5d052b917f2b6e6d7a2de1c09df3ba51910160405180910390a25050610b3d600160c955565b5f8181526101316020908152604091829020600a0180548351818402810184019094528084526060939283018282801561116b57602002820191905f5260205f20905b815481526020019060010190808311611157575b50505050509050919050565b5f8281526065602052604090206001015461119181612741565b61119b8383612bed565b505050565b6001600160a01b03811633146112105760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b606482015260840161081d565b61121a8282612c0e565b5050565b5f51602061409d5f395f51905f5261123581612741565b61123d612c2f565b50565b5f51602061409d5f395f51905f5261125781612741565b6101418290556040518281527fcda03296b648d791f2cee5a5af4b32860d8a3d01fae4126b12b4081224003767906020015b60405180910390a15050565b5f816112ad5f5160206140dd5f395f51905f52612741565b5f8181526101316020526040902060016009820154600160a01b900460ff1660038111156112dd576112dd61389e565b146112fe57604051637196abbf60e01b81526004810183905260240161081d565b60078101546001600160a01b0316331461132e57604051631294b1c360e11b81526004810183905260240161081d565b61133661274b565b61133e612791565b5f8481526101316020526040902061135581612c81565b61135e82612c9a565b825461136a9190613c9e565b6113749190613c9e565b935061138085856127ea565b5061138b600160c955565b5050919050565b5f61139e610135612cb3565b905090565b826113ba5f5160206140dd5f395f51905f52612741565b5f8181526101316020526040902060016009820154600160a01b900460ff1660038111156113ea576113ea61389e565b1461140b57604051637196abbf60e01b81526004810183905260240161081d565b60078101546001600160a01b0316331461143b57604051631294b1c360e11b81526004810183905260240161081d565b61144361274b565b61144b612791565b5f83900361146c576040516335cc39d360e21b815260040160405180910390fd5b5f8581526101316020526040812090600a8201905b8581101561159a575f87878381811061149c5761149c613cb1565b905060200201359050886101325f8381526020019081526020015f2054146114e15760405163b0c13c9f60e01b815260048101829052602481018a905260440161081d565b82545f5b81811015611581578285828154811061150057611500613cb1565b905f5260205f20015403611579578461151a600184613d86565b8154811061152a5761152a613cb1565b905f5260205f20015485828154811061154557611545613cb1565b905f5260205f2001819055508480548061156157611561613d99565b600190038181905f5260205f20015f90559055611581565b6001016114e5565b50505f9081526101326020526040812055600101611481565b505f6115a588611b55565b905082600601548110156115e357600683015460405163a6a6101b60e01b8152600481018a905260248101839052604481019190915260640161081d565b877f02403dfe11b4461cb23bc722e800e5bad3ef47f2b1bd6bad6a40289132fd185d888886600a0160405161161a93929190613d10565b60405180910390a2505050610b3d600160c955565b61163761274b565b61123d81612cd6565b5f54610100900460ff161580801561165e57505f54600160ff909116105b806116775750303b15801561167757505f5460ff166001145b6116da5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161081d565b5f805460ff1916600117905580156116fb575f805461ff0019166101001790555b6001600160a01b038b166117225760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b038a166117495760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b0389166117705760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b0388166117975760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b0387166117be5760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b0386166117e55760405163d92e233d60e01b815260040160405180910390fd5b6117ed612df6565b6117f5612e1c565b6117fd612e4a565b61012d80546001600160a01b03808e166001600160a01b03199283161790925561012e80548d841690831617905561012f80548c84169083161790556101308054928916929091169190911790554261013681905561013d556118605f89612bed565b6118775f51602061409d5f395f51905f5289612bed565b61188e5f5160206140bd5f395f51905f5288612bed565b6118b25f5160206140dd5f395f51905f525f51602061409d5f395f51905f52612e78565b6118d65f5160206140bd5f395f51905f525f51602061409d5f395f51905f52612e78565b5f5b848110156119255761191d5f5160206140dd5f395f51905f5287878481811061190357611903613cb1565b90506020020160208101906119189190613aa1565b612bed565b6001016118d8565b50610140805461ffff191661ffff85169081179091556101418390556040519081527f428d0ce3ec19d535d61922be4f747f68df18c0a0411da1190470f0441d24024c9060200160405180910390a16040518281527fcda03296b648d791f2cee5a5af4b32860d8a3d01fae4126b12b40812240037679060200160405180910390a180156119ec575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050505050505050565b6001600160a01b0381165f908152610138602052604081206108a490612cb3565b5f5160206140bd5f395f51905f52611a3181612741565b61123d612ec2565b5f828152609760205260408120611a509083612eff565b9392505050565b5f9182526065602090815260408084206001600160a01b0393909316845291905290205460ff1690565b5f81815261013160205260408120600a0181805b8254811015611b4d5761012e548354611b39916001600160a01b03169063b45a3c0e90869085908110611aca57611aca613cb1565b905f5260205f2001546040518263ffffffff1660e01b8152600401611af191815260200190565b608060405180830381865afa158015611b0c573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b309190613dd0565b51600f0b612f0a565b611b439083613c9e565b9150600101611a95565b509392505050565b5f5f611b6083611a81565b90505f61012f5f9054906101000a90046001600160a01b03166001600160a01b0316630fdb11cf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611bb4573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611bd89190613e48565b90505f611be48561237c565b9350505050805f03611bfb57505f19949350505050565b80611c068385613e5f565b611c109190613e76565b95945050505050565b611c2161274b565b611c29612f35565b565b5f8181526097602052604081206108a49061300d565b5f82815260656020526040902060010154611c5b81612741565b61119b8383612c0e565b5f51602061409d5f395f51905f52611c7c81612741565b610140805461ffff191661ffff84169081179091556040519081527f428d0ce3ec19d535d61922be4f747f68df18c0a0411da1190470f0441d24024c90602001611289565b5f5f611cce61013c612cb3565b61013e54611cdc9190613c9e565b90505f61013f548211611cef575f611cfd565b61013f54611cfd9083613d86565b90508061013354611d0e9190613c9e565b9250505090565b5f5160206140dd5f395f51905f52611d2c81612741565b611d3461274b565b611d3c612791565b611d4589612ae0565b8a611d635760405163cf17af3760e01b815260040160405180910390fd5b6001600160a01b038a16611d8a5760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b038916611db15760405163d92e233d60e01b815260040160405180910390fd5b875f03611dd157604051631f2a200560e01b815260040160405180910390fd5b5f5f8c81526101316020526040902060090154600160a01b900460ff166003811115611dff57611dff61389e565b14611e205760405163f13a34ab60e01b8152600481018c905260240161081d565b5f849003611e41576040516335cc39d360e21b815260040160405180910390fd5b6014841115611e6657604051638a5b4f9960e01b81526004810185905260240161081d565b5f611e7861ffff808916908a16613e95565b6101405490915061ffff1663ffffffff82161115611ec057610140546040516308371bf960e11b815263ffffffff8316600482015261ffff909116602482015260440161081d565b50610141548861013354611ed49190613c9e565b1115611ee9578761013354610c429190613c9e565b670f43fc2c04ee0000821015611f155760405163802c845d60e01b81526004810183905260240161081d565b818311611f3f5760405163a542244560e01b8152600481018490526024810183905260440161081d565b5f5b84811015612052575f868683818110611f5c57611f5c613cb1565b61012e546040516331a9108f60e11b8152602092909202939093013560048201819052935033926001600160a01b03169150636352211e90602401602060405180830381865afa158015611fb2573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611fd69190613cc5565b6001600160a01b03161461200057604051630e35d34560e11b81526004810182905260240161081d565b5f818152610132602052604090205480156120385760405163f9fa5d9560e01b8152600481018390526024810182905260440161081d565b505f908152610132602052604090208c9055600101611f41565b50604051806101a001604052808981526020015f81526020015f81526020014281526020018861ffff1681526020018761ffff168152602001848152602001838152602001336001600160a01b031681526020018b6001600160a01b031681526020018a6001600160a01b03168152602001600160038111156120d7576120d761389e565b81526020018686808060200260200160405190810160405280939291908181526020018383602002808284375f9201829052509390945250508d81526101316020908152604091829020845181559084015160018201559083015160028201556060830151600380830191909155608084015160048301805460a087015161ffff908116620100000263ffffffff1990921693169290921791909117905560c0840151600583015560e084015160068301556101008401516007830180546001600160a01b039283166001600160a01b031991821617909155610120860151600885018054918416918316919091179055610140860151600985018054919093169181168217835561016087015194955091926001600160a81b03199092161790600160a01b90849081111561220f5761220f61389e565b0217905550610180820151600a8201906122299082613eb1565b509050505f6122378c611b55565b90508281101561226b5760405163a6a6101b60e01b8152600481018d9052602481018290526044810184905260640161081d565b50612278888a8989612b72565b61012d546040516340c10f1960e01b81526001600160a01b03909116906340c10f19906122ab908d908c90600401613d6d565b5f604051808303815f87803b1580156122c2575f5ffd5b505af11580156122d4573d5f5f3e3d5ffd5b50505050896001600160a01b0316336001600160a01b03168c7f71b8cfcb91be8c2c8670be096e68d6366139b0e2d777e4f77ade632a4d7211968b8d8c8c8a8a8e8e60405161232a989796959493929190613f4c565b60405180910390a46119ec600160c955565b5f81815261013160205260408120819081908190819061235b87611b55565b60058201546006909201549098919750955086881094508588109350915050565b5f8181526101316020526040812080549190819081908482036123ab575f5f5f5f9450945094509450506123da565b6123b481612c9a565b93506123bf81612c81565b9250826123cc8587613c9e565b6123d69190613c9e565b9150505b9193509193565b5f5160206140dd5f395f51905f526123f881612741565b61240061274b565b612408612791565b5f8381526101316020526040902060016009820154600160a01b900460ff1660038111156124385761243861389e565b1461245957604051637196abbf60e01b81526004810185905260240161081d565b60078101546001600160a01b0316331461248957604051631294b1c360e11b81526004810185905260240161081d565b60048101545f906124a89061ffff620100009091048116908616613e95565b6101405490915061ffff1663ffffffff821611156124f057610140546040516308371bf960e11b815263ffffffff8316600482015261ffff909116602482015260440161081d565b6009820154612507906001600160a01b0316612ae0565b61251082612af9565b50506004820154825461ffff9091169061252b908287613016565b60048301805461ffff191661ffff878116918217909255604080519284168352602083019190915287917fb393a3069b786b6a3b69171c7aa4df70b1d23b71a3ffde7e19e398e1c49a326491015b60405180910390a250505061119b600160c955565b5f5160206140dd5f395f51905f526125a581612741565b6125ad61274b565b6125b5612791565b5f8381526101316020526040902060016009820154600160a01b900460ff1660038111156125e5576125e561389e565b1461260657604051637196abbf60e01b81526004810185905260240161081d565b60078101546001600160a01b0316331461263657604051631294b1c360e11b81526004810185905260240161081d565b60048101545f9061264e9061ffff8087169116613e95565b6101405490915061ffff1663ffffffff8216111561269657610140546040516308371bf960e11b815263ffffffff8316600482015261ffff909116602482015260440161081d565b60098201546126ad906001600160a01b0316612ae0565b6126b682612af9565b50506004820154825460098401546201000090920461ffff16916126e591906001600160a01b0316838861304a565b60048301805463ffff000019166201000061ffff88811691820292909217909255604080519184168252602082019290925287917f79ceb5b348d77f792cf231e2cc96b3eb0ee412c2fe149d7a3f39b4b9810b11f39101612579565b61123d813361309d565b60fb5460ff1615611c295760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015260640161081d565b600260c954036127e35760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161081d565b600260c955565b805f0361280a57604051631f2a200560e01b815260040160405180910390fd5b5f82815261013160205260409020600981015461282f906001600160a01b0316612ae0565b5f61283982612c81565b61284283612c9a565b61284c9190613c9e565b5f60018401819055600284015542600384015590508061013f5f8282546128739190613c9e565b9091555050808310156128aa57604051633f4c8ac360e11b815260048101859052602481018490526044810182905260640161081d565b5f6128b58285613d86565b83549091508111156128ee5782546040516352da3e7360e01b81526004810187905260248101839052604481019190915260640161081d565b61012d54604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac906129219033908890600401613d6d565b5f604051808303815f87803b158015612938575f5ffd5b505af115801561294a573d5f5f3e3d5ffd5b5050505080835f015f8282546129609190613d86565b9091555050600983015460048401546129949183916001600160a01b039091169061ffff80821691620100009004166130f6565b82545f03612a0a5760098301805460ff60a01b1916600160a11b179055600a83015f5b81548110156129fa576101325f8383815481106129d6576129d6613cb1565b905f5260205f20015481526020019081526020015f205f90558060010190506129b7565b50612a08600a85015f613783565b505b825460405186917f868c03be9ffd10b7bd6294b60684c640d935b4f31deaf6662984e7de7da0708791612a4591888252602082015260400190565b60405180910390a260026009840154600160a01b900460ff166003811115612a6f57612a6f61389e565b03610b3d5760405185907fb77a99aa6bf8135a033a72ab89373f6f8977dc081d277755b7622c1782a14799905f90a25050505050565b600160c955565b5f6001600160e01b03198216637965db0b60e01b14806108a457506301ffc9a760e01b6001600160e01b03198316146108a4565b612ae8612f35565b612af181612cd6565b61123d613171565b60048101545f908190612b1290849061ffff1642613194565b9150612b31838460040160029054906101000a900461ffff1642613194565b905081836001015f828254612b469190613c9e565b9250508190555080836002015f828254612b609190613c9e565b90915550504260039093019290925591565b836101335f828254612b849190613c9e565b92505081905550836101345f828254612b9d9190613c9e565b90915550612bb090506101358584613212565b6001600160a01b0383165f90815261013860205260409020612bd3908583613212565b612be061013c8584613212565b61087a61013c8583613212565b612bf7828261323b565b5f82815260976020526040902061119b90826132c0565b612c1882826132d4565b5f82815260976020526040902061119b908261333a565b612c3761334e565b60fb805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b5f612c8b82613397565b82600201546108a49190613c9e565b5f612ca4826133b5565b82600101546108a49190613c9e565b80545f908103612cc457505f919050565b6108a4825f01548360010154426133cc565b6001600160a01b0381165f90815261013860205260408120612cf7906133f4565b9050801561121a57806101395f828254612d119190613c9e565b90915550506001600160a01b0382165f90815261013a602052604081208054839290612d3e908490613c9e565b909155505061012d546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990612d769085908590600401613d6d565b5f604051808303815f87803b158015612d8d575f5ffd5b505af1158015612d9f573d5f5f3e3d5ffd5b50505050816001600160a01b03167fa71a962c32d0b62575a9e57e1e64b9ee472f6a58755529ed4606f5deca62a52f8261013954604051612dea929190918252602082015260400190565b60405180910390a25050565b5f54610100900460ff16611c295760405162461bcd60e51b815260040161081d90613fa1565b5f54610100900460ff16612e425760405162461bcd60e51b815260040161081d90613fa1565b611c29613410565b5f54610100900460ff16612e705760405162461bcd60e51b815260040161081d90613fa1565b611c29613436565b5f82815260656020526040808220600101805490849055905190918391839186917fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff9190a4505050565b612eca61274b565b60fb805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258612c643390565b5f611a508383613468565b5f5f82600f0b1215612f2e5760405162406f5d60e21b815260040160405180910390fd5b50600f0b90565b5f612f416101356133f4565b9050801561123d57806101375f828254612f5b9190613c9e565b909155505061012d54610130546040516340c10f1960e01b81526001600160a01b03928316926340c10f1992612f98929116908590600401613d6d565b5f604051808303815f87803b158015612faf575f5ffd5b505af1158015612fc1573d5f5f3e3d5ffd5b505050507f3d8708181c6452c5711a2b4c6ed3f12149f6ea35f78549aba00a89d041e766ca8161013754604051613002929190918252602082015260400190565b60405180910390a150565b5f6108a4825490565b613023610135848461348e565b6130306101358483613212565b61303d61013c848461348e565b61119b61013c8483613212565b6001600160a01b0383165f9081526101386020526040902061306d90858461348e565b6001600160a01b0383165f90815261013860205260409020613090908583613212565b612be061013c858461348e565b6130a78282611a57565b61121a576130b4816134ad565b6130bf8360206134bf565b6040516020016130d0929190614003565b60408051601f198184030181529082905262461bcd60e51b825261081d91600401614052565b836101335f8282546131089190613d86565b925050819055508361013b5f8282546131219190613c9e565b909155506131349050610135858461348e565b6001600160a01b0383165f9081526101386020526040902061315790858361348e565b61316461013c858461348e565b61087a61013c858361348e565b61317c61013c6133f4565b61013e5f82825461318d9190613c9e565b9091555050565b825460038401545f91908115806131ad575061ffff8516155b806131b85750808411155b156131c7575f92505050611a50565b5f6131d28286613d86565b90506131e46301e18558612710613e5f565b61ffff87166131f38584613e5f565b6131fd9190613e5f565b6132079190613e76565b979650505050505050565b6132208261ffff8316613e5f565b835f015f8282546132319190613c9e565b9091555050505050565b6132458282611a57565b61121a575f8281526065602090815260408083206001600160a01b03851684529091529020805460ff1916600117905561327c3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b5f611a50836001600160a01b038416613654565b6132de8282611a57565b1561121a575f8281526065602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b5f611a50836001600160a01b0384166136a0565b60fb5460ff16611c295760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015260640161081d565b5f6108a4828360040160029054906101000a900461ffff1642613194565b60048101545f906108a490839061ffff1642613194565b5f806133d88484613d86565b90506133ea6301e18558612710613e5f565b611c068683613e5f565b5f5f6133ff83612cb3565b426001909401939093555090919050565b5f54610100900460ff16612aa55760405162461bcd60e51b815260040161081d90613fa1565b5f54610100900460ff1661345c5760405162461bcd60e51b815260040161081d90613fa1565b60fb805460ff19169055565b5f825f01828154811061347d5761347d613cb1565b905f5260205f200154905092915050565b61349c8261ffff8316613e5f565b835f015f8282546132319190613d86565b60606108a46001600160a01b03831660145b60605f6134cd836002613e5f565b6134d8906002613c9e565b6001600160401b038111156134ef576134ef613dad565b6040519080825280601f01601f191660200182016040528015613519576020820181803683370190505b509050600360fc1b815f8151811061353357613533613cb1565b60200101906001600160f81b03191690815f1a905350600f60fb1b8160018151811061356157613561613cb1565b60200101906001600160f81b03191690815f1a9053505f613583846002613e5f565b61358e906001613c9e565b90505b6001811115613605576f181899199a1a9b1b9c1cb0b131b232b360811b85600f16601081106135c2576135c2613cb1565b1a60f81b8282815181106135d8576135d8613cb1565b60200101906001600160f81b03191690815f1a90535060049490941c936135fe81614087565b9050613591565b508315611a505760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e74604482015260640161081d565b5f81815260018301602052604081205461369957508154600181810184555f8481526020808220909301849055845484825282860190935260409020919091556108a4565b505f6108a4565b5f818152600183016020526040812054801561377a575f6136c2600183613d86565b85549091505f906136d590600190613d86565b9050818114613734575f865f0182815481106136f3576136f3613cb1565b905f5260205f200154905080875f01848154811061371357613713613cb1565b5f918252602080832090910192909255918252600188019052604090208390555b855486908061374557613745613d99565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f9055600193505050506108a4565b5f9150506108a4565b5080545f8255905f5260205f209061123d91905f5b808211156137ad575f81840155600101613798565b505090565b5f5f604083850312156137c3575f5ffd5b50508035926020909101359150565b5f602082840312156137e2575f5ffd5b81356001600160e01b031981168114611a50575f5ffd5b5f5f83601f840112613809575f5ffd5b5081356001600160401b0381111561381f575f5ffd5b6020830191508360208260051b8501011115613839575f5ffd5b9250929050565b5f5f5f60408486031215613852575f5ffd5b8335925060208401356001600160401b0381111561386e575f5ffd5b61387a868287016137f9565b9497909650939450505050565b5f60208284031215613897575f5ffd5b5035919050565b634e487b7160e01b5f52602160045260245ffd5b600481106138ce57634e487b7160e01b5f52602160045260245ffd5b9052565b5f8151808452602084019350602083015f5b828110156139025781518652602095860195909101906001016138e4565b5093949350505050565b60208152815160208201526020820151604082015260408201516060820152606082015160808201525f608083015161394b60a084018261ffff169052565b5060a083015161ffff811660c08401525060c083015160e083015260e083015161010083015261010083015161398d6101208401826001600160a01b03169052565b506101208301516001600160a01b038116610140840152506101408301516001600160a01b038116610160840152506101608301516139d06101808401826138b2565b506101808301516101a0808401526139ec6101c08401826138d2565b949350505050565b5f5f5f60608486031215613a06575f5ffd5b505081359360208301359350604090920135919050565b602080825282518282018190525f918401906040840190835b81811015613a54578351835260209384019390920191600101613a36565b509095945050505050565b6001600160a01b038116811461123d575f5ffd5b5f5f60408385031215613a84575f5ffd5b823591506020830135613a9681613a5f565b809150509250929050565b5f60208284031215613ab1575f5ffd5b8135611a5081613a5f565b803561ffff81168114613acd575f5ffd5b919050565b5f5f5f5f5f5f5f5f5f5f6101208b8d031215613aec575f5ffd5b8a35613af781613a5f565b995060208b0135613b0781613a5f565b985060408b0135613b1781613a5f565b975060608b0135613b2781613a5f565b965060808b0135613b3781613a5f565b955060a08b0135613b4781613a5f565b945060c08b01356001600160401b03811115613b61575f5ffd5b613b6d8d828e016137f9565b9095509350613b80905060e08c01613abc565b91505f6101008c01359050809150509295989b9194979a5092959850565b5f60208284031215613bae575f5ffd5b611a5082613abc565b5f5f5f5f5f5f5f5f5f5f6101208b8d031215613bd1575f5ffd5b8a35995060208b0135613be381613a5f565b985060408b0135613bf381613a5f565b975060608b01359650613c0860808c01613abc565b9550613c1660a08c01613abc565b945060c08b01356001600160401b03811115613c30575f5ffd5b613c3c8d828e016137f9565b9b9e9a9d50989b979a969995989760e0810135966101009091013595509350505050565b5f5f60408385031215613c71575f5ffd5b82359150613c8160208401613abc565b90509250929050565b634e487b7160e01b5f52601160045260245ffd5b808201808211156108a4576108a4613c8a565b634e487b7160e01b5f52603260045260245ffd5b5f60208284031215613cd5575f5ffd5b8151611a5081613a5f565b8183525f6001600160fb1b03831115613cf7575f5ffd5b8260051b80836020870137939093016020019392505050565b604081525f613d23604083018587613ce0565b8281036020840152808454808352602083019150855f5260205f2092505f5b81811015613d60578354835260019384019360209093019201613d42565b5090979650505050505050565b6001600160a01b03929092168252602082015260400190565b818103818111156108a4576108a4613c8a565b634e487b7160e01b5f52603160045260245ffd5b634e487b7160e01b5f52604160045260245ffd5b80518015158114613acd575f5ffd5b5f6080828403128015613de1575f5ffd5b50604051608081016001600160401b0381118282101715613e0457613e04613dad565b6040528251600f81900b8114613e18575f5ffd5b815260208381015190820152613e3060408401613dc1565b60408201526060928301519281019290925250919050565b5f60208284031215613e58575f5ffd5b5051919050565b80820281158282048414176108a4576108a4613c8a565b5f82613e9057634e487b7160e01b5f52601260045260245ffd5b500490565b63ffffffff81811683821601908111156108a4576108a4613c8a565b81516001600160401b03811115613eca57613eca613dad565b600160401b811115613ede57613ede613dad565b815481835580821015613f1257825f528160205f20018282035f5b81811015613f0e575f83820155600101613ef9565b5050505b5060208301613f26835f9081526020902090565b5f5b83811015613f4457825182820155602090920191600101613f28565b505050505050565b88815260018060a01b038816602082015261ffff8716604082015261ffff861660608201528460808201528360a082015260e060c08201525f613f9360e083018486613ce0565b9a9950505050505050505050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b5f81518060208401855e5f93019283525090919050565b76020b1b1b2b9b9a1b7b73a3937b61d1030b1b1b7bab73a1604d1b81525f61402e6017830185613fec565b7001034b99036b4b9b9b4b733903937b6329607d1b8152611c106011820185613fec565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b5f8161409557614095613c8a565b505f19019056fe71840dc4906352362b0cdaf79870196c8e42acafade72d5d5a6d59291253ceb165d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862ae99d769f717ef5998d23b311cb6df42c9f772c997399f5192f2452542a0d8ca0a2646970667358221220a064fecc57b9daea8677cadef7b9380b32443c637ed4ba2cc82956b1492e2a2864736f6c63430008210033","name":"EnclaveDebtManager","is_blueprint":false,"license_type":"none","is_fully_verified":true,"has_methods_read_proxy":false,"is_vyper_contract":false,"is_verified_via_eth_bytecode_db":false,"language":"solidity","evm_version":"osaka","can_be_visualized_via_sol2uml":false,"has_methods_write_proxy":false,"has_custom_methods_read":false,"is_verified_via_sourcify":false,"additional_sources":[{"file_path":"@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (access/AccessControlEnumerable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IAccessControlEnumerableUpgradeable.sol\";\nimport \"./AccessControlUpgradeable.sol\";\nimport \"../utils/structs/EnumerableSetUpgradeable.sol\";\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerableUpgradeable is Initializable, IAccessControlEnumerableUpgradeable, AccessControlUpgradeable {\n    using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet;\n\n    mapping(bytes32 => EnumerableSetUpgradeable.AddressSet) private _roleMembers;\n\n    function __AccessControlEnumerable_init() internal onlyInitializing {\n    }\n\n    function __AccessControlEnumerable_init_unchained() internal onlyInitializing {\n    }\n    /**\n     * @dev See {IERC165-supportsInterface}.\n     */\n    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n        return interfaceId == type(IAccessControlEnumerableUpgradeable).interfaceId || super.supportsInterface(interfaceId);\n    }\n\n    /**\n     * @dev Returns one of the accounts that have `role`. `index` must be a\n     * value between 0 and {getRoleMemberCount}, non-inclusive.\n     *\n     * Role bearers are not sorted in any particular way, and their ordering may\n     * change at any point.\n     *\n     * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n     * you perform all queries on the same block. See the following\n     * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n     * for more information.\n     */\n    function getRoleMember(bytes32 role, uint256 index) public view virtual override returns (address) {\n        return _roleMembers[role].at(index);\n    }\n\n    /**\n     * @dev Returns the number of accounts that have `role`. Can be used\n     * together with {getRoleMember} to enumerate all bearers of a role.\n     */\n    function getRoleMemberCount(bytes32 role) public view virtual override returns (uint256) {\n        return _roleMembers[role].length();\n    }\n\n    /**\n     * @dev Overload {_grantRole} to track enumerable memberships\n     */\n    function _grantRole(bytes32 role, address account) internal virtual override {\n        super._grantRole(role, account);\n        _roleMembers[role].add(account);\n    }\n\n    /**\n     * @dev Overload {_revokeRole} to track enumerable memberships\n     */\n    function _revokeRole(bytes32 role, address account) internal virtual override {\n        super._revokeRole(role, account);\n        _roleMembers[role].remove(account);\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/access/AccessControlUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (access/AccessControl.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IAccessControlUpgradeable.sol\";\nimport \"../utils/ContextUpgradeable.sol\";\nimport \"../utils/StringsUpgradeable.sol\";\nimport \"../utils/introspection/ERC165Upgradeable.sol\";\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n *     require(hasRole(MY_ROLE, msg.sender));\n *     ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControlUpgradeable, ERC165Upgradeable {\n    struct RoleData {\n        mapping(address => bool) members;\n        bytes32 adminRole;\n    }\n\n    mapping(bytes32 => RoleData) private _roles;\n\n    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n    /**\n     * @dev Modifier that checks that an account has a specific role. Reverts\n     * with a standardized message including the required role.\n     *\n     * The format of the revert reason is given by the following regular expression:\n     *\n     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\n     *\n     * _Available since v4.1._\n     */\n    modifier onlyRole(bytes32 role) {\n        _checkRole(role);\n        _;\n    }\n\n    function __AccessControl_init() internal onlyInitializing {\n    }\n\n    function __AccessControl_init_unchained() internal onlyInitializing {\n    }\n    /**\n     * @dev See {IERC165-supportsInterface}.\n     */\n    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n        return interfaceId == type(IAccessControlUpgradeable).interfaceId || super.supportsInterface(interfaceId);\n    }\n\n    /**\n     * @dev Returns `true` if `account` has been granted `role`.\n     */\n    function hasRole(bytes32 role, address account) public view virtual override returns (bool) {\n        return _roles[role].members[account];\n    }\n\n    /**\n     * @dev Revert with a standard message if `_msgSender()` is missing `role`.\n     * Overriding this function changes the behavior of the {onlyRole} modifier.\n     *\n     * Format of the revert message is described in {_checkRole}.\n     *\n     * _Available since v4.6._\n     */\n    function _checkRole(bytes32 role) internal view virtual {\n        _checkRole(role, _msgSender());\n    }\n\n    /**\n     * @dev Revert with a standard message if `account` is missing `role`.\n     *\n     * The format of the revert reason is given by the following regular expression:\n     *\n     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\n     */\n    function _checkRole(bytes32 role, address account) internal view virtual {\n        if (!hasRole(role, account)) {\n            revert(\n                string(\n                    abi.encodePacked(\n                        \"AccessControl: account \",\n                        StringsUpgradeable.toHexString(account),\n                        \" is missing role \",\n                        StringsUpgradeable.toHexString(uint256(role), 32)\n                    )\n                )\n            );\n        }\n    }\n\n    /**\n     * @dev Returns the admin role that controls `role`. See {grantRole} and\n     * {revokeRole}.\n     *\n     * To change a role's admin, use {_setRoleAdmin}.\n     */\n    function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {\n        return _roles[role].adminRole;\n    }\n\n    /**\n     * @dev Grants `role` to `account`.\n     *\n     * If `account` had not been already granted `role`, emits a {RoleGranted}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     *\n     * May emit a {RoleGranted} event.\n     */\n    function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\n        _grantRole(role, account);\n    }\n\n    /**\n     * @dev Revokes `role` from `account`.\n     *\n     * If `account` had been granted `role`, emits a {RoleRevoked} event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     *\n     * May emit a {RoleRevoked} event.\n     */\n    function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\n        _revokeRole(role, account);\n    }\n\n    /**\n     * @dev Revokes `role` from the calling account.\n     *\n     * Roles are often managed via {grantRole} and {revokeRole}: this function's\n     * purpose is to provide a mechanism for accounts to lose their privileges\n     * if they are compromised (such as when a trusted device is misplaced).\n     *\n     * If the calling account had been revoked `role`, emits a {RoleRevoked}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must be `account`.\n     *\n     * May emit a {RoleRevoked} event.\n     */\n    function renounceRole(bytes32 role, address account) public virtual override {\n        require(account == _msgSender(), \"AccessControl: can only renounce roles for self\");\n\n        _revokeRole(role, account);\n    }\n\n    /**\n     * @dev Grants `role` to `account`.\n     *\n     * If `account` had not been already granted `role`, emits a {RoleGranted}\n     * event. Note that unlike {grantRole}, this function doesn't perform any\n     * checks on the calling account.\n     *\n     * May emit a {RoleGranted} event.\n     *\n     * [WARNING]\n     * ====\n     * This function should only be called from the constructor when setting\n     * up the initial roles for the system.\n     *\n     * Using this function in any other way is effectively circumventing the admin\n     * system imposed by {AccessControl}.\n     * ====\n     *\n     * NOTE: This function is deprecated in favor of {_grantRole}.\n     */\n    function _setupRole(bytes32 role, address account) internal virtual {\n        _grantRole(role, account);\n    }\n\n    /**\n     * @dev Sets `adminRole` as ``role``'s admin role.\n     *\n     * Emits a {RoleAdminChanged} event.\n     */\n    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n        bytes32 previousAdminRole = getRoleAdmin(role);\n        _roles[role].adminRole = adminRole;\n        emit RoleAdminChanged(role, previousAdminRole, adminRole);\n    }\n\n    /**\n     * @dev Grants `role` to `account`.\n     *\n     * Internal function without access restriction.\n     *\n     * May emit a {RoleGranted} event.\n     */\n    function _grantRole(bytes32 role, address account) internal virtual {\n        if (!hasRole(role, account)) {\n            _roles[role].members[account] = true;\n            emit RoleGranted(role, account, _msgSender());\n        }\n    }\n\n    /**\n     * @dev Revokes `role` from `account`.\n     *\n     * Internal function without access restriction.\n     *\n     * May emit a {RoleRevoked} event.\n     */\n    function _revokeRole(bytes32 role, address account) internal virtual {\n        if (hasRole(role, account)) {\n            _roles[role].members[account] = false;\n            emit RoleRevoked(role, account, _msgSender());\n        }\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/access/IAccessControlEnumerableUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControlEnumerable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IAccessControlUpgradeable.sol\";\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerableUpgradeable is IAccessControlUpgradeable {\n    /**\n     * @dev Returns one of the accounts that have `role`. `index` must be a\n     * value between 0 and {getRoleMemberCount}, non-inclusive.\n     *\n     * Role bearers are not sorted in any particular way, and their ordering may\n     * change at any point.\n     *\n     * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n     * you perform all queries on the same block. See the following\n     * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n     * for more information.\n     */\n    function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n    /**\n     * @dev Returns the number of accounts that have `role`. Can be used\n     * together with {getRoleMember} to enumerate all bearers of a role.\n     */\n    function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable/access/IAccessControlUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControlUpgradeable {\n    /**\n     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n     *\n     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n     * {RoleAdminChanged} not being emitted signaling this.\n     *\n     * _Available since v3.1._\n     */\n    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n    /**\n     * @dev Emitted when `account` is granted `role`.\n     *\n     * `sender` is the account that originated the contract call, an admin role\n     * bearer except when using {AccessControl-_setupRole}.\n     */\n    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n    /**\n     * @dev Emitted when `account` is revoked `role`.\n     *\n     * `sender` is the account that originated the contract call:\n     *   - if using `revokeRole`, it is the admin role bearer\n     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)\n     */\n    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n    /**\n     * @dev Returns `true` if `account` has been granted `role`.\n     */\n    function hasRole(bytes32 role, address account) external view returns (bool);\n\n    /**\n     * @dev Returns the admin role that controls `role`. See {grantRole} and\n     * {revokeRole}.\n     *\n     * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n     */\n    function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n    /**\n     * @dev Grants `role` to `account`.\n     *\n     * If `account` had not been already granted `role`, emits a {RoleGranted}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     */\n    function grantRole(bytes32 role, address account) external;\n\n    /**\n     * @dev Revokes `role` from `account`.\n     *\n     * If `account` had been granted `role`, emits a {RoleRevoked} event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     */\n    function revokeRole(bytes32 role, address account) external;\n\n    /**\n     * @dev Revokes `role` from the calling account.\n     *\n     * Roles are often managed via {grantRole} and {revokeRole}: this function's\n     * purpose is to provide a mechanism for accounts to lose their privileges\n     * if they are compromised (such as when a trusted device is misplaced).\n     *\n     * If the calling account had been granted `role`, emits a {RoleRevoked}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must be `account`.\n     */\n    function renounceRole(bytes32 role, address account) external;\n}\n"},{"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/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/interfaces/IERC4906.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC4906.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC165.sol\";\nimport \"./IERC721.sol\";\n\n/// @title EIP-721 Metadata Update Extension\ninterface IERC4906 is IERC165, IERC721 {\n    /// @dev This event emits when the metadata of a token is changed.\n    /// So that the third-party platforms such as NFT market could\n    /// timely update the images and related attributes of the NFT.\n    event MetadataUpdate(uint256 _tokenId);\n\n    /// @dev This event emits when the metadata of a range of tokens is changed.\n    /// So that the third-party platforms such as NFT market could\n    /// timely update the images and related attributes of the NFTs.\n    event BatchMetadataUpdate(uint256 _fromTokenId, uint256 _toTokenId);\n}\n"},{"file_path":"@openzeppelin/contracts/interfaces/IERC6372.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC6372.sol)\n\npragma solidity ^0.8.0;\n\ninterface IERC6372 {\n    /**\n     * @dev Clock used for flagging checkpoints. Can be overridden to implement timestamp based checkpoints (and voting).\n     */\n    function clock() external view returns (uint48);\n\n    /**\n     * @dev Description of the clock\n     */\n    // solhint-disable-next-line func-name-mixedcase\n    function CLOCK_MODE() external view returns (string memory);\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":"@openzeppelin/contracts-upgradeable/utils/StringsUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./math/MathUpgradeable.sol\";\nimport \"./math/SignedMathUpgradeable.sol\";\n\n/**\n * @dev String operations.\n */\nlibrary StringsUpgradeable {\n    bytes16 private constant _SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        unchecked {\n            uint256 length = MathUpgradeable.log10(value) + 1;\n            string memory buffer = new string(length);\n            uint256 ptr;\n            /// @solidity memory-safe-assembly\n            assembly {\n                ptr := add(buffer, add(32, length))\n            }\n            while (true) {\n                ptr--;\n                /// @solidity memory-safe-assembly\n                assembly {\n                    mstore8(ptr, byte(mod(value, 10), _SYMBOLS))\n                }\n                value /= 10;\n                if (value == 0) break;\n            }\n            return buffer;\n        }\n    }\n\n    /**\n     * @dev Converts a `int256` to its ASCII `string` decimal representation.\n     */\n    function toString(int256 value) internal pure returns (string memory) {\n        return string(abi.encodePacked(value < 0 ? \"-\" : \"\", toString(SignedMathUpgradeable.abs(value))));\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        unchecked {\n            return toHexString(value, MathUpgradeable.log256(value) + 1);\n        }\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i > 1; --i) {\n            buffer[i] = _SYMBOLS[value & 0xf];\n            value >>= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n\n    /**\n     * @dev Returns true if the two strings are equal.\n     */\n    function equal(string memory a, string memory b) internal pure returns (bool) {\n        return keccak256(bytes(a)) == keccak256(bytes(b));\n    }\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC165Upgradeable.sol\";\nimport {Initializable} from \"../../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n *\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\n */\nabstract contract ERC165Upgradeable is Initializable, IERC165Upgradeable {\n    function __ERC165_init() internal onlyInitializing {\n    }\n\n    function __ERC165_init_unchained() internal onlyInitializing {\n    }\n    /**\n     * @dev See {IERC165-supportsInterface}.\n     */\n    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n        return interfaceId == type(IERC165Upgradeable).interfaceId;\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":"@openzeppelin/contracts-upgradeable/utils/introspection/IERC165Upgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165Upgradeable {\n    /**\n     * @dev Returns true if this contract implements the interface defined by\n     * `interfaceId`. See the corresponding\n     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n     * to learn more about how these ids are created.\n     *\n     * This function call must use less than 30 000 gas.\n     */\n    function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary MathUpgradeable {\n    enum Rounding {\n        Down, // Toward negative infinity\n        Up, // Toward infinity\n        Zero // Toward zero\n    }\n\n    /**\n     * @dev Returns the largest of two numbers.\n     */\n    function max(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a > b ? a : b;\n    }\n\n    /**\n     * @dev Returns the smallest of two numbers.\n     */\n    function min(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a < b ? a : b;\n    }\n\n    /**\n     * @dev Returns the average of two numbers. The result is rounded towards\n     * zero.\n     */\n    function average(uint256 a, uint256 b) internal pure returns (uint256) {\n        // (a + b) / 2 can overflow.\n        return (a & b) + (a ^ b) / 2;\n    }\n\n    /**\n     * @dev Returns the ceiling of the division of two numbers.\n     *\n     * This differs from standard division with `/` in that it rounds up instead\n     * of rounding down.\n     */\n    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n        // (a + b - 1) / b can overflow on addition, so we distribute.\n        return a == 0 ? 0 : (a - 1) / b + 1;\n    }\n\n    /**\n     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\n     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\n     * with further edits by Uniswap Labs also under MIT license.\n     */\n    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {\n        unchecked {\n            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\n            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n            // variables such that product = prod1 * 2^256 + prod0.\n            uint256 prod0; // Least significant 256 bits of the product\n            uint256 prod1; // Most significant 256 bits of the product\n            assembly {\n                let mm := mulmod(x, y, not(0))\n                prod0 := mul(x, y)\n                prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n            }\n\n            // Handle non-overflow cases, 256 by 256 division.\n            if (prod1 == 0) {\n                // Solidity will revert if denominator == 0, unlike the div opcode on its own.\n                // The surrounding unchecked block does not change this fact.\n                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.\n                return prod0 / denominator;\n            }\n\n            // Make sure the result is less than 2^256. Also prevents denominator == 0.\n            require(denominator > prod1, \"Math: mulDiv overflow\");\n\n            ///////////////////////////////////////////////\n            // 512 by 256 division.\n            ///////////////////////////////////////////////\n\n            // Make division exact by subtracting the remainder from [prod1 prod0].\n            uint256 remainder;\n            assembly {\n                // Compute remainder using mulmod.\n                remainder := mulmod(x, y, denominator)\n\n                // Subtract 256 bit number from 512 bit number.\n                prod1 := sub(prod1, gt(remainder, prod0))\n                prod0 := sub(prod0, remainder)\n            }\n\n            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\n            // See https://cs.stackexchange.com/q/138556/92363.\n\n            // Does not overflow because the denominator cannot be zero at this stage in the function.\n            uint256 twos = denominator & (~denominator + 1);\n            assembly {\n                // Divide denominator by twos.\n                denominator := div(denominator, twos)\n\n                // Divide [prod1 prod0] by twos.\n                prod0 := div(prod0, twos)\n\n                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\n                twos := add(div(sub(0, twos), twos), 1)\n            }\n\n            // Shift in bits from prod1 into prod0.\n            prod0 |= prod1 * twos;\n\n            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\n            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\n            // four bits. That is, denominator * inv = 1 mod 2^4.\n            uint256 inverse = (3 * denominator) ^ 2;\n\n            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\n            // in modular arithmetic, doubling the correct bits in each step.\n            inverse *= 2 - denominator * inverse; // inverse mod 2^8\n            inverse *= 2 - denominator * inverse; // inverse mod 2^16\n            inverse *= 2 - denominator * inverse; // inverse mod 2^32\n            inverse *= 2 - denominator * inverse; // inverse mod 2^64\n            inverse *= 2 - denominator * inverse; // inverse mod 2^128\n            inverse *= 2 - denominator * inverse; // inverse mod 2^256\n\n            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\n            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\n            // is no longer required.\n            result = prod0 * inverse;\n            return result;\n        }\n    }\n\n    /**\n     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\n     */\n    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {\n        uint256 result = mulDiv(x, y, denominator);\n        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\n            result += 1;\n        }\n        return result;\n    }\n\n    /**\n     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\n     *\n     * Inspired by Henry S. Warren, Jr.'s \"Hacker's Delight\" (Chapter 11).\n     */\n    function sqrt(uint256 a) internal pure returns (uint256) {\n        if (a == 0) {\n            return 0;\n        }\n\n        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\n        //\n        // We know that the \"msb\" (most significant bit) of our target number `a` is a power of 2 such that we have\n        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\n        //\n        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\n        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\n        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\n        //\n        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\n        uint256 result = 1 << (log2(a) >> 1);\n\n        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\n        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\n        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\n        // into the expected uint128 result.\n        unchecked {\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            return min(result, a / result);\n        }\n    }\n\n    /**\n     * @notice Calculates sqrt(a), following the selected rounding direction.\n     */\n    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = sqrt(a);\n            return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 2, rounded down, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log2(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >> 128 > 0) {\n                value >>= 128;\n                result += 128;\n            }\n            if (value >> 64 > 0) {\n                value >>= 64;\n                result += 64;\n            }\n            if (value >> 32 > 0) {\n                value >>= 32;\n                result += 32;\n            }\n            if (value >> 16 > 0) {\n                value >>= 16;\n                result += 16;\n            }\n            if (value >> 8 > 0) {\n                value >>= 8;\n                result += 8;\n            }\n            if (value >> 4 > 0) {\n                value >>= 4;\n                result += 4;\n            }\n            if (value >> 2 > 0) {\n                value >>= 2;\n                result += 2;\n            }\n            if (value >> 1 > 0) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log2(value);\n            return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 10, rounded down, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log10(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >= 10 ** 64) {\n                value /= 10 ** 64;\n                result += 64;\n            }\n            if (value >= 10 ** 32) {\n                value /= 10 ** 32;\n                result += 32;\n            }\n            if (value >= 10 ** 16) {\n                value /= 10 ** 16;\n                result += 16;\n            }\n            if (value >= 10 ** 8) {\n                value /= 10 ** 8;\n                result += 8;\n            }\n            if (value >= 10 ** 4) {\n                value /= 10 ** 4;\n                result += 4;\n            }\n            if (value >= 10 ** 2) {\n                value /= 10 ** 2;\n                result += 2;\n            }\n            if (value >= 10 ** 1) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log10(value);\n            return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 256, rounded down, of a positive value.\n     * Returns 0 if given 0.\n     *\n     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\n     */\n    function log256(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >> 128 > 0) {\n                value >>= 128;\n                result += 16;\n            }\n            if (value >> 64 > 0) {\n                value >>= 64;\n                result += 8;\n            }\n            if (value >> 32 > 0) {\n                value >>= 32;\n                result += 4;\n            }\n            if (value >> 16 > 0) {\n                value >>= 16;\n                result += 2;\n            }\n            if (value >> 8 > 0) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log256(value);\n            return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);\n        }\n    }\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable/utils/math/SignedMathUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Standard signed math utilities missing in the Solidity language.\n */\nlibrary SignedMathUpgradeable {\n    /**\n     * @dev Returns the largest of two signed numbers.\n     */\n    function max(int256 a, int256 b) internal pure returns (int256) {\n        return a > b ? a : b;\n    }\n\n    /**\n     * @dev Returns the smallest of two signed numbers.\n     */\n    function min(int256 a, int256 b) internal pure returns (int256) {\n        return a < b ? a : b;\n    }\n\n    /**\n     * @dev Returns the average of two signed numbers without overflow.\n     * The result is rounded towards zero.\n     */\n    function average(int256 a, int256 b) internal pure returns (int256) {\n        // Formula from the book \"Hacker's Delight\"\n        int256 x = (a & b) + ((a ^ b) >> 1);\n        return x + (int256(uint256(x) >> 255) & (a ^ b));\n    }\n\n    /**\n     * @dev Returns the absolute unsigned value of a signed value.\n     */\n    function abs(int256 n) internal pure returns (uint256) {\n        unchecked {\n            // must be unchecked in order to support `n = type(int256).min`\n            return uint256(n >= 0 ? n : -n);\n        }\n    }\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable/utils/structs/EnumerableSetUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n *     // Add the library methods\n *     using EnumerableSet for EnumerableSet.AddressSet;\n *\n *     // Declare a set state variable\n *     EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSetUpgradeable {\n    // To implement this library for multiple types with as little code\n    // repetition as possible, we write it in terms of a generic Set type with\n    // bytes32 values.\n    // The Set implementation uses private functions, and user-facing\n    // implementations (such as AddressSet) are just wrappers around the\n    // underlying Set.\n    // This means that we can only create new EnumerableSets for types that fit\n    // in bytes32.\n\n    struct Set {\n        // Storage of set values\n        bytes32[] _values;\n        // Position of the value in the `values` array, plus 1 because index 0\n        // means a value is not in the set.\n        mapping(bytes32 => uint256) _indexes;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function _add(Set storage set, bytes32 value) private returns (bool) {\n        if (!_contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._indexes[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\n        // We read and store the value's index to prevent multiple reads from the same storage slot\n        uint256 valueIndex = set._indexes[value];\n\n        if (valueIndex != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 toDeleteIndex = valueIndex - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (lastIndex != toDeleteIndex) {\n                bytes32 lastValue = set._values[lastIndex];\n\n                // Move the last value to the index where the value to delete is\n                set._values[toDeleteIndex] = lastValue;\n                // Update the index for the moved value\n                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the index for the deleted slot\n            delete set._indexes[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\n        return set._indexes[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function _length(Set storage set) private view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function _values(Set storage set) private view returns (bytes32[] memory) {\n        return set._values;\n    }\n\n    // Bytes32Set\n\n    struct Bytes32Set {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _add(set._inner, value);\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _remove(set._inner, value);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n        return _contains(set._inner, value);\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(Bytes32Set storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n        return _at(set._inner, index);\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        bytes32[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // AddressSet\n\n    struct AddressSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(AddressSet storage set, address value) internal returns (bool) {\n        return _add(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(AddressSet storage set, address value) internal returns (bool) {\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(AddressSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\n        return address(uint160(uint256(_at(set._inner, index))));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(AddressSet storage set) internal view returns (address[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        address[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintSet\n\n    struct UintSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\n        return _add(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\n        return _remove(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(UintSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n        return uint256(_at(set._inner, index));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(UintSet storage set) internal view returns (uint256[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        uint256[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n}\n"},{"file_path":"@openzeppelin/contracts/interfaces/IERC165.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (interfaces/IERC165.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/introspection/IERC165.sol\";\n"},{"file_path":"@openzeppelin/contracts/interfaces/IERC721.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (interfaces/IERC721.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../token/ERC721/IERC721.sol\";\n"},{"file_path":"@openzeppelin/contracts/token/ERC721/IERC721.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../../utils/introspection/IERC165.sol\";\n\n/**\n * @dev Required interface of an ERC721 compliant contract.\n */\ninterface IERC721 is IERC165 {\n    /**\n     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);\n\n    /**\n     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.\n     */\n    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);\n\n    /**\n     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.\n     */\n    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n    /**\n     * @dev Returns the number of tokens in ``owner``'s account.\n     */\n    function balanceOf(address owner) external view returns (uint256 balance);\n\n    /**\n     * @dev Returns the owner of the `tokenId` token.\n     *\n     * Requirements:\n     *\n     * - `tokenId` must exist.\n     */\n    function ownerOf(uint256 tokenId) external view returns (address owner);\n\n    /**\n     * @dev Safely transfers `tokenId` token from `from` to `to`.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must exist and be owned by `from`.\n     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n     *\n     * Emits a {Transfer} event.\n     */\n    function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;\n\n    /**\n     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\n     * are aware of the ERC721 protocol to prevent tokens from being forever locked.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must exist and be owned by `from`.\n     * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.\n     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n     *\n     * Emits a {Transfer} event.\n     */\n    function safeTransferFrom(address from, address to, uint256 tokenId) external;\n\n    /**\n     * @dev Transfers `tokenId` token from `from` to `to`.\n     *\n     * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721\n     * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must\n     * understand this adds an external call which potentially creates a reentrancy vulnerability.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must be owned by `from`.\n     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address from, address to, uint256 tokenId) external;\n\n    /**\n     * @dev Gives permission to `to` to transfer `tokenId` token to another account.\n     * The approval is cleared when the token is transferred.\n     *\n     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.\n     *\n     * Requirements:\n     *\n     * - The caller must own the token or be an approved operator.\n     * - `tokenId` must exist.\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address to, uint256 tokenId) external;\n\n    /**\n     * @dev Approve or remove `operator` as an operator for the caller.\n     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.\n     *\n     * Requirements:\n     *\n     * - The `operator` cannot be the caller.\n     *\n     * Emits an {ApprovalForAll} event.\n     */\n    function setApprovalForAll(address operator, bool approved) external;\n\n    /**\n     * @dev Returns the account approved for `tokenId` token.\n     *\n     * Requirements:\n     *\n     * - `tokenId` must exist.\n     */\n    function getApproved(uint256 tokenId) external view returns (address operator);\n\n    /**\n     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.\n     *\n     * See {setApprovalForAll}\n     */\n    function isApprovedForAll(address owner, address operator) external view returns (bool);\n}\n"},{"file_path":"@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC721.sol\";\n\n/**\n * @title ERC-721 Non-Fungible Token Standard, optional metadata extension\n * @dev See https://eips.ethereum.org/EIPS/eip-721\n */\ninterface IERC721Metadata is IERC721 {\n    /**\n     * @dev Returns the token collection name.\n     */\n    function name() external view returns (string memory);\n\n    /**\n     * @dev Returns the token collection symbol.\n     */\n    function symbol() external view returns (string memory);\n\n    /**\n     * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.\n     */\n    function tokenURI(uint256 tokenId) external view returns (string memory);\n}\n"},{"file_path":"@openzeppelin/contracts/utils/introspection/IERC165.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n    /**\n     * @dev Returns true if this contract implements the interface defined by\n     * `interfaceId`. See the corresponding\n     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n     * to learn more about how these ids are created.\n     *\n     * This function call must use less than 30 000 gas.\n     */\n    function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n"},{"file_path":"contracts/governance/IVotes.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.33;\n\n/// Modified IVotes interface for tokenId based voting\ninterface IVotes {\n    /**\n     * @dev Emitted when an account changes their delegate.\n     */\n    event DelegateChanged(\n        address indexed delegator,\n        uint256 indexed fromDelegate,\n        uint256 indexed toDelegate\n    );\n\n    /**\n     * @dev Emitted when a token transfer or delegate change results in changes to a delegate's number of votes.\n     */\n    event DelegateVotesChanged(\n        address indexed delegate,\n        uint256 previousBalance,\n        uint256 newBalance\n    );\n\n    /**\n     * @dev Returns the amount of votes that `tokenId` had at a specific moment in the past.\n     *      If the account passed in is not the owner, returns 0.\n     */\n    function getPastVotes(\n        address account,\n        uint256 tokenId,\n        uint256 timepoint\n    ) external view returns (uint256);\n\n    /**\n     * @dev Returns the total supply of votes available at a specific moment in the past. If the `clock()` is\n     * configured to use block numbers, this will return the value the end of the corresponding block.\n     *\n     * NOTE: This value is the sum of all available votes, which is not necessarily the sum of all delegated votes.\n     * Votes that have not been delegated are still part of total supply, even though they would not participate in a\n     * vote.\n     */\n    function getPastTotalSupply(\n        uint256 timepoint\n    ) external view returns (uint256);\n\n    /**\n     * @dev Returns the delegate that `tokenId` has chosen. Can never be equal to the delegator's `tokenId`.\n     *      Returns 0 if not delegated.\n     */\n    function delegates(uint256 tokenId) external view returns (uint256);\n\n    /**\n     * @dev Delegates votes from the sender to `delegatee`.\n     */\n    function delegate(uint256 delegator, uint256 delegatee) external;\n\n    /**\n     * @dev Delegates votes from `delegator` to `delegatee`. Signer must own `delegator`.\n     */\n    function delegateBySig(\n        uint256 delegator,\n        uint256 delegatee,\n        uint256 nonce,\n        uint256 expiry,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external;\n}\n"},{"file_path":"contracts/interfaces/IVotingEscrow.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.33;\n\nimport {IERC165, IERC721, IERC721Metadata} from \"@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol\";\nimport {IERC6372} from \"@openzeppelin/contracts/interfaces/IERC6372.sol\";\nimport {IERC4906} from \"@openzeppelin/contracts/interfaces/IERC4906.sol\";\nimport {IVotes} from \"../governance/IVotes.sol\";\n\ninterface IVotingEscrow is IVotes, IERC4906, IERC6372, IERC721Metadata {\n    /// @notice Structure containing foundational properties of a locked balance (veNFT).\n    struct LockedBalance {\n        /// @notice The physical amount of tokens locked.\n        int128 amount;\n        /// @notice The timestamp when the lock expires.\n        uint256 end;\n        /// @notice Flag indicating if the lock is permanent.\n        ///         When true, all tokens in the veNFT are permanently locked.\n        ///         Permanent locks apply to the entire amount - there is no way\n        ///         to lock permanently just a portion of tokens from the veNFT.\n        bool isPermanent;\n        /// @notice The boost factor applied to the veNFT's voting power.\n        ///         The boost factor is dynamic and changes over time.\n        uint256 boost;\n    }\n\n    /// @notice Checkpoint structure holding a snapshot of the bias and slope,\n    ///         specific to a single veNFT, at a certain timestamp.\n    ///         Bias and slope are properties of the linear function describing\n    ///         the veNFT's (decaying) voting power over time. The bias and slope\n    ///         are derived from the LockedBalance properties. Each change to the\n    ///         LockedBalance properties triggers an update of the bias and slope\n    ///         and creation of a new checkpoint that captures the updated values.\n    struct UserPoint {\n        /// @notice Bias of the voting power linear function.\n        ///         Describes the initial voting power of the veNFT at the checkpoint timestamp.\n        int128 bias;\n        /// @notice Slope of the voting power linear function.\n        ///         Describes the per-second rate at which the voting power decays over time.\n        int128 slope;\n        /// @notice Timestamp of the checkpoint.\n        uint256 ts;\n        /// @notice Block number of the checkpoint.\n        uint256 blk;\n        /// @notice The amount of tokens locked permanently in this veNFT.\n        ///         If the veNFT is not permanently locked, this value is 0.\n        ///         If the veNFT is permanently locked, this value equals the full locked amount.\n        uint256 permanent;\n        /// @notice The `bias` property with boost factor applied.\n        int128 virtualBias;\n        /// @notice The `slope` property with boost factor applied.\n        int128 virtualSlope;\n        /// @notice The `permanent` property with boost factor applied.\n        uint256 virtualPermanent;\n    }\n\n    /// @notice Global checkpoint structure holding a snapshot of the bias and slope,\n    ///         specific to the aggregate of all veNFTs, at a certain timestamp.\n    ///         Bias and slope are properties of the linear function describing\n    ///         the (decaying) total voting power over time. The bias and slope\n    ///         are an aggregate of all individual veNFTs' biases and slopes.\n    ///         Each change to the LockedBalance properties of any veNFT triggers\n    ///         an update of the global bias and slope and creation of a new global\n    ///         checkpoint that captures the updated values.\n    struct GlobalPoint {\n        /// @notice Bias of the total voting power linear function.\n        ///         Describes the initial total voting power at the global checkpoint timestamp.\n        int128 bias;\n        /// @notice Slope of the total voting power linear function.\n        ///         Describes the per-second rate at which the total voting power decays over time.\n        int128 slope;\n        /// @notice Timestamp of the global checkpoint.\n        uint256 ts;\n        /// @notice Block number of the global checkpoint.\n        uint256 blk;\n        /// @notice The total amount of tokens locked permanently across all veNFTs.\n        ///         When a veNFT is permanently locked, its entire locked amount is included here.\n        uint256 permanentLockBalance;\n        /// @notice The `bias` property with all veNFTs' boost factors applied.\n        int128 virtualBias;\n        /// @notice The `slope` property with all veNFTs' boost factors applied.\n        int128 virtualSlope;\n        /// @notice The `permanentLockBalance` property with all veNFTs' boost factors applied.\n        uint256 virtualPermanentLockBalance;\n    }\n\n    /// @notice Checkpoint structure holding a voting power delegation at a certain timestamp.\n    ///         Each checkpoint is specific to a single veNFT.\n    struct Checkpoint {\n        /// @notice Timestamp of the checkpoint.\n        uint256 fromTimestamp;\n        /// @notice Owner of the checkpoint's veNFT.\n        address owner;\n        /// @notice Balance delegated to the checkpoint's veNFT. As only permanently-locked veNFTs\n        ///         can delegate, this balance represents a summarized voting power coming from\n        ///         the delegating veNFTs. Delegated balance includes the boost factors of the delegators.\n        uint256 delegatedBalance;\n        /// @notice Another veNFT that the checkpoint's veNFT is delegating its own balance to.\n        ///         Bear in mind, it's possible to delegate only own balance but not re-delegate\n        ///         the delegated balance coming from delegating veNFTs. For example, if A\n        ///         delegates to B, and B delegates to C, A has 0 VP, B has VP from A only,\n        ///         and C has VP from B + their own VP.\n        uint256 delegatee;\n    }\n\n    enum DepositType {\n        DEPOSIT_FOR_TYPE,\n        CREATE_LOCK_TYPE,\n        INCREASE_LOCK_AMOUNT,\n        INCREASE_UNLOCK_TIME\n    }\n\n    /// @dev Different types of veNFTs:\n    /// NORMAL  - typical veNFT\n    /// LOCKED  - veNFT which is locked into a MANAGED veNFT\n    /// MANAGED - veNFT which can accept the deposit of NORMAL veNFTs\n    enum EscrowType {\n        NORMAL,\n        LOCKED,\n        MANAGED\n    }\n\n    error AlreadyVoted();\n    error AmountTooBig();\n    error ERC721ReceiverRejectedTokens();\n    error ERC721TransferToNonERC721ReceiverImplementer();\n    error InvalidNonce();\n    error InvalidSignature();\n    error InvalidSignatureS();\n    error InvalidManagedNFTId();\n    error LockDurationNotInFuture();\n    error LockDurationTooLong();\n    error LockExpired();\n    error LockNotExpired();\n    error NoLockFound();\n    error NonExistentToken();\n    error NotApprovedOrOwner();\n    error NotDistributor();\n    error NotEmergencyCouncilOrGovernor();\n    error NotGovernor();\n    error NotGovernorOrManager();\n    error NotManagedNFT();\n    error NotManagedOrNormalNFT();\n    error NotLockedNFT();\n    error NotNormalNFT();\n    error NotPermanentLock();\n    error NotOwner();\n    error NotTeam();\n    error NotVoter();\n    error OwnershipChange();\n    error PermanentLock();\n    error SameAddress();\n    error SameNFT();\n    error SameState();\n    error SplitNoOwner();\n    error SplitNotAllowed();\n    error SignatureExpired();\n    error TooManyTokenIDs();\n    error ZeroAddress();\n    error ZeroAmount();\n    error ZeroBalance();\n    error NotGrantManager();\n    error IncorrectGrantVestingRange();\n    error IncorrectGrantVestingCliff();\n    error UnvestedGrantNFT();\n    error NotGrantNFT();\n    error GrantWithoutVestedAmount();\n    error GrantFullyVested();\n    error SplitsDisabled();\n    error NotBooster();\n    error NotAllowedGrantManager();\n\n    event Deposit(\n        address indexed provider,\n        uint256 indexed tokenId,\n        DepositType indexed depositType,\n        uint256 value,\n        uint256 locktime,\n        uint256 ts\n    );\n    event Withdraw(\n        address indexed provider,\n        uint256 indexed tokenId,\n        uint256 value,\n        uint256 ts\n    );\n    event LockPermanent(\n        address indexed _owner,\n        uint256 indexed _tokenId,\n        uint256 amount,\n        uint256 _ts\n    );\n    event UnlockPermanent(\n        address indexed _owner,\n        uint256 indexed _tokenId,\n        uint256 amount,\n        uint256 _ts\n    );\n    event Supply(uint256 prevSupply, uint256 supply);\n    event Merge(\n        address indexed _sender,\n        uint256 indexed _from,\n        uint256 indexed _to,\n        uint256 _amountFrom,\n        uint256 _amountTo,\n        uint256 _amountFinal,\n        uint256 _locktime,\n        uint256 _ts\n    );\n    event Split(\n        uint256 indexed _from,\n        uint256 indexed _tokenId1,\n        uint256 indexed _tokenId2,\n        address _sender,\n        uint256 _splitAmount1,\n        uint256 _splitAmount2,\n        uint256 _locktime,\n        uint256 _ts\n    );\n    event CreateManaged(\n        address indexed _to,\n        uint256 indexed _mTokenId,\n        address indexed _from,\n        address _lockedManagedReward,\n        address _freeManagedReward\n    );\n    event DepositManaged(\n        address indexed _owner,\n        uint256 indexed _tokenId,\n        uint256 indexed _mTokenId,\n        uint256 _weight,\n        uint256 _ts\n    );\n    event WithdrawManaged(\n        address indexed _owner,\n        uint256 indexed _tokenId,\n        uint256 indexed _mTokenId,\n        uint256 _weight,\n        uint256 _ts\n    );\n    event SetAllowedManager(address indexed _allowedManager);\n    event CreateGrant(\n        uint256 indexed _tokenId,\n        address _grantee,\n        address _grantManager,\n        uint256 _vestingStart,\n        uint256 _vestingEnd,\n        uint256 _cliffEnd\n    );\n    event SetGrantManager(address indexed _grantManager);\n    event RevokeGrant(\n        uint256 indexed _tokenId,\n        address indexed _grantManager,\n        uint256 _revokedAmount,\n        uint256 _remainingAmount\n    );\n    event SetGrantManagerAllowed(address indexed _grantManager, bool _allowed);\n    /// @notice Emitted when the boost factor is updated for a veNFT.\n    /// @param _tokenId The ID of the veNFT whose boost was updated.\n    /// @param _boost The new boost factor value.\n    event UpdateBoost(uint256 indexed _tokenId, uint256 _boost);\n    event SetBooster(address indexed _booster);\n    event SetFactoryRegistry(address indexed _factoryRegistry);\n    event AddSecondaryVoter(address indexed _voter);\n\n    // State variables\n    /// @notice Address of Meta-tx Forwarder\n    function forwarder() external view returns (address);\n\n    /// @notice Address of FactoryRegistry.sol\n    function factoryRegistry() external view returns (address);\n\n    /// @notice Address of token used to create a veNFT\n    function token() external view returns (address);\n\n    /// @notice Address of RewardsDistributor.sol\n    function distributor() external view returns (address);\n\n    /// @notice Address of Voter.sol\n    function voter() external view returns (address);\n\n    /// @notice Address of Protocol Team multisig\n    function team() external view returns (address);\n\n    /// @dev address which can create managed NFTs\n    function allowedManager() external view returns (address);\n\n    /// @dev Returns true if `_account` is allowed to act as a grant manager.\n    function isGrantManagerAllowed(\n        address _account\n    ) external view returns (bool);\n\n    /// @dev Current count of token\n    function tokenId() external view returns (uint256);\n\n    /*///////////////////////////////////////////////////////////////\n                            MANAGED NFT STORAGE\n    //////////////////////////////////////////////////////////////*/\n\n    /// @dev Mapping of token id to escrow type\n    ///      Takes advantage of the fact default value is EscrowType.NORMAL\n    function escrowType(uint256 tokenId) external view returns (EscrowType);\n\n    /// @dev Mapping of token id to managed id\n    function idToManaged(\n        uint256 tokenId\n    ) external view returns (uint256 managedTokenId);\n\n    /// @dev Mapping of user token id to managed token id to weight of token id\n    function weights(\n        uint256 tokenId,\n        uint256 managedTokenId\n    ) external view returns (uint256 weight);\n\n    /// @dev Mapping of managed id to deactivated state\n    function deactivated(uint256 tokenId) external view returns (bool inactive);\n\n    /// @dev Mapping from managed nft id to locked managed rewards\n    ///      `token` denominated rewards (rebases/rewards) stored in locked managed rewards contract\n    ///      to prevent co-mingling of assets\n    function managedToLocked(uint256 tokenId) external view returns (address);\n\n    /// @dev Mapping from managed nft id to free managed rewards contract\n    ///      these rewards can be freely withdrawn by users\n    function managedToFree(uint256 tokenId) external view returns (address);\n\n    /*///////////////////////////////////////////////////////////////\n                            MANAGED NFT LOGIC\n    //////////////////////////////////////////////////////////////*/\n\n    /// @notice Create managed NFT (a permanent lock) for use within ecosystem.\n    /// @dev Throws if address already owns a managed NFT.\n    /// @return _mTokenId managed token id.\n    function createManagedLockFor(\n        address _to\n    ) external returns (uint256 _mTokenId);\n\n    /// @notice Delegates balance to managed nft\n    ///         Note that NFTs deposited into a managed NFT will be re-locked\n    ///         to the maximum lock time on withdrawal.\n    ///         Permanent locks that are deposited will automatically unlock.\n    /// @dev Managed nft will remain max-locked as long as there is at least one\n    ///      deposit or withdrawal per week.\n    ///      Throws if deposit nft is managed.\n    ///      Throws if recipient nft is not managed.\n    ///      Throws if deposit nft is already locked.\n    ///      Throws if not called by voter.\n    /// @param _tokenId tokenId of NFT being deposited\n    /// @param _mTokenId tokenId of managed NFT that will receive the deposit\n    function depositManaged(uint256 _tokenId, uint256 _mTokenId) external;\n\n    /// @notice Retrieves locked rewards and withdraws balance from managed nft.\n    ///         Note that the NFT withdrawn is re-locked to the maximum lock time.\n    /// @dev Throws if NFT not locked.\n    ///      Throws if not called by voter.\n    /// @param _tokenId tokenId of NFT being deposited.\n    function withdrawManaged(uint256 _tokenId) external;\n\n    /// @notice Permit one address to call createManagedLockFor() that is not Voter.governor()\n    function setAllowedManager(address _allowedManager) external;\n\n    /// @notice Add or remove `_grantManager` from the set of addresses allowed\n    ///         to act as grant managers. Only callable by the team.\n    /// @param _grantManager Address to update.\n    /// @param _allowed True to add to allowlist, false to remove.\n    function setGrantManagerAllowed(\n        address _grantManager,\n        bool _allowed\n    ) external;\n\n    /// @notice Set Managed NFT state. Inactive NFTs cannot be deposited into.\n    /// @param _mTokenId managed nft state to set\n    /// @param _state true => inactive, false => active\n    function setManagedState(uint256 _mTokenId, bool _state) external;\n\n    /*///////////////////////////////////////////////////////////////\n                             METADATA STORAGE\n    //////////////////////////////////////////////////////////////*/\n\n    function name() external view returns (string memory);\n\n    function symbol() external view returns (string memory);\n\n    function version() external view returns (string memory);\n\n    function decimals() external view returns (uint8);\n\n    function setTeam(address _team) external;\n\n    /// @notice Set the entity authorized to update the boost for a veNFT\n    /// @param _booster The new booster address\n    /// @dev Requirements:\n    ///      - The caller must be the team\n    ///      - The booster address must implement IVotingEscrowBooster\n    function setBooster(address _booster) external;\n\n    /// @notice Address of the entity authorized to update the boost for a veNFT\n    function booster() external view returns (address);\n\n    /// @notice Set the factory registry address\n    /// @param _factoryRegistry The new factory registry address\n    /// @dev Requirements:\n    ///      - The caller must be the team\n    ///      - The factory registry address must not be zero address\n    function setFactoryRegistry(address _factoryRegistry) external;\n\n    /// @inheritdoc IERC721Metadata\n    function tokenURI(uint256 tokenId) external view returns (string memory);\n\n    /*//////////////////////////////////////////////////////////////\n                      ERC721 BALANCE/OWNER STORAGE\n    //////////////////////////////////////////////////////////////*/\n\n    /// @dev Mapping from owner address to mapping of index to tokenId\n    function ownerToNFTokenIdList(\n        address _owner,\n        uint256 _index\n    ) external view returns (uint256 _tokenId);\n\n    /// @inheritdoc IERC721\n    function ownerOf(uint256 tokenId) external view returns (address owner);\n\n    /// @inheritdoc IERC721\n    function balanceOf(address owner) external view returns (uint256 balance);\n\n    /*//////////////////////////////////////////////////////////////\n                         ERC721 APPROVAL STORAGE\n    //////////////////////////////////////////////////////////////*/\n\n    /// @inheritdoc IERC721\n    function getApproved(\n        uint256 _tokenId\n    ) external view returns (address operator);\n\n    /// @inheritdoc IERC721\n    function isApprovedForAll(\n        address owner,\n        address operator\n    ) external view returns (bool);\n\n    /// @notice Check whether spender is owner or an approved user for a given veNFT\n    /// @param _spender .\n    /// @param _tokenId .\n    function isApprovedOrOwner(\n        address _spender,\n        uint256 _tokenId\n    ) external returns (bool);\n\n    /*//////////////////////////////////////////////////////////////\n                              ERC721 LOGIC\n    //////////////////////////////////////////////////////////////*/\n\n    /// @inheritdoc IERC721\n    function approve(address to, uint256 tokenId) external;\n\n    /// @inheritdoc IERC721\n    function setApprovalForAll(address operator, bool approved) external;\n\n    /// @inheritdoc IERC721\n    function transferFrom(address from, address to, uint256 tokenId) external;\n\n    /// @inheritdoc IERC721\n    function safeTransferFrom(\n        address from,\n        address to,\n        uint256 tokenId\n    ) external;\n\n    /// @inheritdoc IERC721\n    function safeTransferFrom(\n        address from,\n        address to,\n        uint256 tokenId,\n        bytes calldata data\n    ) external;\n\n    /*//////////////////////////////////////////////////////////////\n                              ERC165 LOGIC\n    //////////////////////////////////////////////////////////////*/\n\n    /// @inheritdoc IERC165\n    function supportsInterface(\n        bytes4 _interfaceID\n    ) external view returns (bool);\n\n    /*//////////////////////////////////////////////////////////////\n                             ESCROW STORAGE\n    //////////////////////////////////////////////////////////////*/\n\n    /// @notice Total count of epochs witnessed since contract creation\n    function epoch() external view returns (uint256);\n\n    /// @notice Total amount of token() deposited.\n    /// @dev This is NOT the total voting power but total amount of physical tokens deposited.\n    function supply() external view returns (uint256);\n\n    /// @notice Summarized voting power of all permanently locked veNFTs.\n    ///         For example, if there are 3 veNFTs with 100 tokens each,\n    ///         and 2 of them are permanently locked, the permanentLockBalance\n    ///         will be 200.\n    function permanentLockBalance() external view returns (uint256);\n\n    function userPointEpoch(\n        uint256 _tokenId\n    ) external view returns (uint256 _epoch);\n\n    /// @notice time -> signed slope change\n    function slopeChanges(uint256 _timestamp) external view returns (int128);\n\n    /// @notice account -> can split\n    function canSplit(address _account) external view returns (bool);\n\n    /// @notice Global point history at a given index\n    function pointHistory(\n        uint256 _loc\n    ) external view returns (GlobalPoint memory);\n\n    /// @notice Get the LockedBalance (amount, end) of a _tokenId\n    /// @param _tokenId .\n    /// @return LockedBalance of _tokenId\n    function locked(\n        uint256 _tokenId\n    ) external view returns (LockedBalance memory);\n\n    /// @notice User -> UserPoint[userEpoch]\n    function userPointHistory(\n        uint256 _tokenId,\n        uint256 _loc\n    ) external view returns (UserPoint memory);\n\n    /*//////////////////////////////////////////////////////////////\n                              ESCROW LOGIC\n    //////////////////////////////////////////////////////////////*/\n\n    /// @notice Record global data to checkpoint\n    function checkpoint() external;\n\n    /// @notice Deposit `_value` tokens for `_tokenId` and add to the lock\n    /// @dev Anyone (even a smart contract) can deposit for someone else, but\n    ///      cannot extend their locktime and deposit for a brand new user\n    /// @param _tokenId lock NFT\n    /// @param _value Amount to add to user's lock\n    function depositFor(uint256 _tokenId, uint256 _value) external;\n\n    /// @notice Deposit `_value` tokens for `msg.sender` and lock for `_lockDuration`\n    /// @param _value Amount to deposit\n    /// @param _lockDuration Number of seconds to lock tokens for (rounded down to nearest week)\n    /// @return TokenId of created veNFT\n    function createLock(\n        uint256 _value,\n        uint256 _lockDuration\n    ) external returns (uint256);\n\n    /// @notice Deposit `_value` tokens for `_to` and lock for `_lockDuration`\n    /// @param _value Amount to deposit\n    /// @param _lockDuration Number of seconds to lock tokens for (rounded down to nearest week)\n    /// @param _to Address to deposit\n    /// @return TokenId of created veNFT\n    function createLockFor(\n        uint256 _value,\n        uint256 _lockDuration,\n        address _to\n    ) external returns (uint256);\n\n    /// @notice Deposit `_value` additional tokens for `_tokenId` without\n    ///         modifying the unlock time.\n    /// @dev Reverts if called for a veNFT representing a grant and the grant\n    ///      has not fully vested yet.\n    /// @param _value Amount of tokens to deposit and add to the lock\n    function increaseAmount(uint256 _tokenId, uint256 _value) external;\n\n    /// @notice Extend the unlock time for `_tokenId`\n    ///         Cannot extend lock time of permanent locks\n    /// @param _lockDuration New number of seconds until tokens unlock\n    function increaseUnlockTime(\n        uint256 _tokenId,\n        uint256 _lockDuration\n    ) external;\n\n    /// @notice Withdraw all tokens for `_tokenId`\n    /// @dev Only possible if the lock is both expired and not permanent\n    ///      This will burn the veNFT. Any rebases or rewards that are unclaimed\n    ///      will no longer be claimable. Claim all rebases and rewards prior to calling this.\n    function withdraw(uint256 _tokenId) external;\n\n    /// @notice Merges `_from` into `_to`.\n    /// @dev Cannot merge `_from` locks that are permanent or have already voted this epoch.\n    ///      Cannot merge `_to` locks that have already expired.\n    ///      Cannot merge if either `_from` or `_to` is veNFT created for\n    ///      a grant that has not fully vested yet.\n    ///      This will burn the veNFT. Any rebases or rewards that are unclaimed\n    ///      will no longer be claimable. Claim all rebases and rewards prior to calling this.\n    /// @param _from VeNFT to merge from.\n    /// @param _to VeNFT to merge into.\n    function merge(uint256 _from, uint256 _to) external;\n\n    /// @notice Splits veNFT into two new veNFTS - one with oldLocked.amount - `_amount`, and the second with `_amount`\n    /// @dev    This burns the tokenId of the target veNFT\n    ///         Callable by approved or owner\n    ///         If this is called by approved, approved will not have permissions to manipulate the newly created veNFTs\n    ///         Returns the two new split veNFTs to owner\n    ///         If `from` is permanent, will automatically dedelegate.\n    ///         This will burn the veNFT. Any rebases or rewards that are unclaimed\n    ///         will no longer be claimable. Claim all rebases and rewards prior to calling this.\n    /// @param _from VeNFT to split.\n    /// @param _amount Amount to split from veNFT.\n    /// @return _tokenId1 Return tokenId of veNFT with oldLocked.amount - `_amount`.\n    /// @return _tokenId2 Return tokenId of veNFT with `_amount`.\n    function split(\n        uint256 _from,\n        uint256 _amount\n    ) external returns (uint256 _tokenId1, uint256 _tokenId2);\n\n    /// @notice Toggle split for a specific address.\n    /// @dev Toggle split for address(0) to enable or disable for all.\n    /// @param _account Address to toggle split permissions\n    /// @param _bool True to allow, false to disallow\n    function toggleSplit(address _account, bool _bool) external;\n\n    /// @notice Permanently lock a veNFT. Voting power will be equal to\n    ///         `LockedBalance.amount` with no decay. Required to delegate.\n    /// @dev Only callable by unlocked normal veNFTs.\n    /// @param _tokenId tokenId to lock.\n    function lockPermanent(uint256 _tokenId) external;\n\n    /// @notice Unlock a permanently locked veNFT. Voting power will decay.\n    ///         Will automatically dedelegate if delegated.\n    /// @dev Only callable by permanently locked veNFTs.\n    ///      Cannot unlock if already voted this epoch.\n    /// @param _tokenId tokenId to unlock.\n    function unlockPermanent(uint256 _tokenId) external;\n\n    /*///////////////////////////////////////////////////////////////\n                             VOTING STORAGE\n    //////////////////////////////////////////////////////////////*/\n\n    /// @notice Get the virtual (boosted) voting power for _tokenId at the\n    ///         current timestamp.\n    /// @dev Returns 0 if called in the same block as a transfer.\n    /// @param _tokenId veNFT ID to query the voting power for\n    /// @return Current voting power for _tokenId\n    function votingPowerOfNFT(uint256 _tokenId) external view returns (uint256);\n\n    /// @notice Get the unboosted voting power for _tokenId at the current\n    ///         timestamp. Unboosted voting power is the voting power without\n    ///         the boost factor applied.\n    /// @dev Similar to `votingPowerOfNFT(uint256 _tokenId)` but without the\n    ///      boost factor applied. Returns 0 if called in the same block as\n    ///      transfer.\n    /// @param _tokenId veNFT ID to query unboosted voting power for\n    /// @return Unboosted voting power for _tokenId at the current timestamp\n    function unboostedVotingPowerOfNFT(\n        uint256 _tokenId\n    ) external view returns (uint256);\n\n    /// @notice Get the virtual (boosted) voting power for _tokenId at a given\n    ///         timestamp\n    /// @param _tokenId veNFT ID to query the voting power for\n    /// @param _t Timestamp to query voting power\n    /// @return Voting power for _tokenId at timestamp _t\n    function votingPowerOfNFTAt(\n        uint256 _tokenId,\n        uint256 _t\n    ) external view returns (uint256);\n\n    /// @notice Get the unboosted voting power for _tokenId at a given timestamp.\n    ///         Unboosted voting power is the voting power without the boost\n    ///         factor applied.\n    /// @dev Similar to `votingPowerOfNFTAt(uint256 _tokenId, uint256 _t)` but\n    ///      without the boost factor applied.\n    /// @param _tokenId veNFT ID to query unboosted voting power for\n    /// @param _t Timestamp to query unboosted voting power\n    /// @return Unboosted voting power for _tokenId at timestamp _t\n    function unboostedVotingPowerOfNFTAt(\n        uint256 _tokenId,\n        uint256 _t\n    ) external view returns (uint256);\n\n    /// @notice Calculate total virtual (boosted) voting power at the current\n    ///         timestamp\n    /// @return Total voting power at current timestamp\n    function totalVotingPower() external view returns (uint256);\n\n    /// @notice Calculate unboosted total voting power at the current timestamp.\n    ///         Unboosted total voting power is the total voting power without\n    ///         the boost factors applied.\n    /// @dev Similar to `totalVotingPower()` but without the boost factors applied.\n    /// @return Unboosted total voting power at current timestamp\n    function unboostedTotalVotingPower() external view returns (uint256);\n\n    /// @notice Calculate total virtual (boosted) voting power at a given\n    ///         timestamp.\n    /// @param _t Timestamp to query total voting power\n    /// @return Total voting power at given timestamp\n    function totalVotingPowerAt(uint256 _t) external view returns (uint256);\n\n    /// @notice Calculate unboosted total voting power at a given timestamp.\n    ///         Unboosted total voting power is the total voting power without\n    ///         the boost factors applied.\n    /// @dev Similar to `totalVotingPowerAt(uint256 _t)` but without the boost\n    ///      factors applied.\n    /// @param _t Timestamp to query unboosted total voting power.\n    /// @return Unboosted total voting power at given timestamp.\n    function unboostedTotalVotingPowerAt(\n        uint256 _t\n    ) external view returns (uint256);\n\n    /// @notice Summarized virtual (boosted) voting power of all permanently\n    ///         locked veNFTs. For example, if there are 3 veNFTs with 100\n    ///         tokens and 2x boost each, and 2 of them are permanently locked,\n    ///         the virtualPermanentLockBalance will be 400.\n    /// @dev Same as `permanentLockBalance()` but with the boost factors applied.\n    function virtualPermanentLockBalance() external view returns (uint256);\n\n    /// @notice time -> signed virtual slope change (with boost applied)\n    function virtualSlopeChanges(\n        uint256 _timestamp\n    ) external view returns (int128);\n\n    /*///////////////////////////////////////////////////////////////\n                               VOTING LOGIC\n    //////////////////////////////////////////////////////////////*/\n\n    /// @notice Updates the voting power boost for a veNFT\n    /// @param _tokenId veNFT token ID\n    /// @param _boost New boost value. This is a value in BoostLibrary.PRECISION precision.\n    ///               0 is a valid value and means the same as 1x boost (or no boost).\n    ///               A negative boost (< 1x) is also allowed. The caller is responsible\n    ///               for ensuring the boost value makes sense in a broader context.\n    /// @dev Requirements:\n    ///      - The caller must be the booster\n    ///      - The veNFT must exist\n    ///      - The veNFT must be a normal or managed NFT\n    ///      - The veNFT must be unexpired or permanent lock\n    function updateBoost(uint256 _tokenId, uint256 _boost) external;\n\n    /// @notice See if a queried _tokenId has actively voted in\n    ///         the primary voter or any of the secondary voters.\n    /// @param _tokenId .\n    /// @return True if voted, else false\n    function voted(uint256 _tokenId) external view returns (bool);\n\n    /// @notice Get the list of voters that a token has voted in, regardless of the epoch.\n    /// @param _tokenId The token ID to query\n    /// @return Array of voter addresses that the token has voted in\n    function votedVoters(\n        uint256 _tokenId\n    ) external view returns (address[] memory);\n\n    /// @notice Get the number of voters that a token has voted in\n    /// @param _tokenId The token ID to query\n    /// @return The number of voters that the token has voted in\n    function votedVotersLength(\n        uint256 _tokenId\n    ) external view returns (uint256);\n\n    /// @notice Check if an address is a secondary voter\n    /// @param _voter The address to check\n    /// @return True if the address is a secondary voter, else false\n    function isSecondaryVoter(address _voter) external view returns (bool);\n\n    /// @notice Add an address to the secondary voters set.\n    /// @param _voter The address to add\n    /// @dev This contract distinguishes between primary voter (returned by `voter()`) and secondary voters.\n    ///      The primary voter has additional responsibilities, most importantly, it manages deposits and\n    ///      withdrawals for managed NFTs (as the only controller of free and locked managed rewards).\n    /// @dev WARNING: Once added, a secondary voter CANNOT be removed.\n    /// @dev Requirements:\n    ///      - The caller must be the team\n    ///      - The voter address must not be zero address\n    function addSecondaryVoter(address _voter) external;\n\n    /// @notice Set the global state voter and distributor\n    /// @dev The caller must be the team\n    /// @dev WARNING: Setting this on a live instance is a critical change\n    ///      affecting the entire system. MAKE SURE YOU KNOW WHAT YOU ARE DOING!\n    function setVoterAndDistributor(\n        address _voter,\n        address _distributor\n    ) external;\n\n    /// @notice Set `voted` for _tokenId to true or false\n    /// @dev Only callable by voter\n    /// @param _tokenId .\n    /// @param _voted .\n    function voting(uint256 _tokenId, bool _voted) external;\n\n    /*///////////////////////////////////////////////////////////////\n                            DAO VOTING STORAGE\n    //////////////////////////////////////////////////////////////*/\n\n    /// @notice The number of checkpoints for each tokenId\n    function numCheckpoints(uint256 tokenId) external view returns (uint48);\n\n    /// @notice A record of states for signing / validating signatures\n    function nonces(address account) external view returns (uint256);\n\n    /// @inheritdoc IVotes\n    function delegates(uint256 delegator) external view returns (uint256);\n\n    /// @notice A record of delegated token checkpoints for each account, by index\n    /// @param tokenId .\n    /// @param index .\n    /// @return Checkpoint\n    function checkpoints(\n        uint256 tokenId,\n        uint48 index\n    ) external view returns (Checkpoint memory);\n\n    /// @inheritdoc IVotes\n    function getPastVotes(\n        address account,\n        uint256 tokenId,\n        uint256 timestamp\n    ) external view returns (uint256);\n\n    /// @inheritdoc IVotes\n    function getPastTotalSupply(\n        uint256 timestamp\n    ) external view returns (uint256);\n\n    /*///////////////////////////////////////////////////////////////\n                             DAO VOTING LOGIC\n    //////////////////////////////////////////////////////////////*/\n\n    /// @inheritdoc IVotes\n    function delegate(uint256 delegator, uint256 delegatee) external;\n\n    /// @inheritdoc IVotes\n    function delegateBySig(\n        uint256 delegator,\n        uint256 delegatee,\n        uint256 nonce,\n        uint256 expiry,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external;\n\n    /*//////////////////////////////////////////////////////////////\n                              ERC6372 LOGIC\n    //////////////////////////////////////////////////////////////*/\n\n    /// @inheritdoc IERC6372\n    function clock() external view returns (uint48);\n\n    /// @inheritdoc IERC6372\n    function CLOCK_MODE() external view returns (string memory);\n\n    /*///////////////////////////////////////////////////////////////\n                                TOKEN GRANT\n    //////////////////////////////////////////////////////////////*/\n\n    /// @notice Deposit `_value` of tokens as a grant and lock until `_vestingEnd`\n    ///         with the provided `_grantManager`. The vesting range must be\n    ///         correct, i.e. _vestingStart < _vestingEnd. The function can only\n    ///         be executed when the current block time is before `_vestingEnd`.\n    ///         The specified _grantManager must be on the list of allowed\n    ///         grant managers.\n    /// @param _value Amount to deposit\n    /// @param _grantee The grantee's address\n    /// @param _grantManager The grant manager who can revoke the grant\n    /// @param _vestingStart The timestamp representing the start of the vesting\n    ///        schedule. This value might be different than the start of the\n    ///        actual lock. The reason for this is that there might be a delay\n    ///        between creating the grant in the third party service and\n    ///        converting to a lock by executing this function.\n    /// @param _vestingEnd The timestamp representing the end of the vesting\n    ///        schedule. The lock will be rounded up to nearest week but the\n    ///        original vesting end is recorded in the contract.\n    /// @param _cliffEnd The timestamp representing the end of the cliff. The\n    ///        cliff starts at _vestingStart. If there is no cliff, this value\n    ///        should be set to value equal _vestingStart.\n    /// @return TokenId of created veNFT\n    function createGrantLockFor(\n        uint256 _value,\n        address _grantee,\n        address _grantManager,\n        uint256 _vestingStart,\n        uint256 _vestingEnd,\n        uint256 _cliffEnd\n    ) external returns (uint256);\n\n    /// @notice Allows the existing grant manager to transfer grant management\n    ///         rights to a new address. Setting the grant manager to the zero\n    ///         address makes the grant irrevocable. Once set to zero, the grant\n    ///         manager cannot be reassigned.\n    /// @param _tokenId tokenId of the veNFT\n    /// @param _newGrantManager The new grant manager address\n    function setGrantManager(\n        uint256 _tokenId,\n        address _newGrantManager\n    ) external;\n\n    /// @notice Allows the grant manager to revoke a grant. If there are vested\n    ///         tokens, they remain in the veNFT and the unvested portion is\n    ///         transferred to the grant manager. If there are no vested tokens\n    ///         (vesting has not started yet or we are before the cliff), all\n    ///         grant tokens are transferred to the grant manager. Rebase rewards\n    ///         already added to the veNFT stay with the grantee in the veNFT.\n    ///         If there are no rebase rewards already added, the veNFT is kept\n    ///         as a 1-unit dust position owned by the grant manager. The grant\n    ///         manager should manually claim rebases to the NFT revoked before\n    ///         calling this function.\n    /// @dev    Reverts if the veNFT was not created as a grant or if vesting\n    ///         has already ended. When there are no rebase rewards already\n    ///         added, leaving a 1-unit dust veNFT instead of burning allows to\n    ///         avoiding burning veNFTs before the lock end. Note that the veNFT\n    ///         may still have active votes on multiple voters that would\n    ///         otherwise have had to be reset to zero before burning.\n    function revokeGrant(uint256 _tokenId) external;\n\n    /// @notice Returns the grant manager address for the given veNFT\n    /// @param _tokenId tokenId of the veNFT\n    function grantManager(uint256 _tokenId) external view returns (address);\n\n    /// @notice Returns the vesting schedule start for the given veNFT.\n    ///         Zero if the veNFT was not created as a grant.\n    /// @param _tokenId tokenId of the veNFT\n    function vestingStart(uint256 _tokenId) external view returns (uint256);\n\n    /// @notice Returns the vesting schedule end for the given veNFT.\n    ///         Zero if the veNFT was not created as a grant.\n    /// @param _tokenId tokenId of the veNFT\n    function vestingEnd(uint256 _tokenId) external view returns (uint256);\n\n    /// @notice Returns the cliff end for the given veNFT.\n    ///         Zero if the veNFT was not created as a grant.\n    /// @param _tokenId tokenId of the veNFT\n    function cliffEnd(uint256 _tokenId) external view returns (uint256);\n\n    /// @notice Returns the cumulative rebase amount deposited by the\n    ///         RewardsDistributor while the grant was still unvested.\n    ///         Zero if the veNFT was not created as a grant or has no\n    ///         accumulated rebases.\n    /// @param _tokenId tokenId of the veNFT\n    function grantRebaseAmount(\n        uint256 _tokenId\n    ) external view returns (uint256);\n}\n"},{"file_path":"contracts/libraries/SafeCastLibrary.sol","source_code":"// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.33;\n\n/// @title SafeCast Library\n/// @author velodrome.finance\n/// @notice Safely convert unsigned and signed integers without overflow / underflow\nlibrary SafeCastLibrary {\n    error SafeCastOverflow();\n    error SafeCastUnderflow();\n\n    /// @dev Safely convert uint256 to int128\n    function toInt128(uint256 value) internal pure returns (int128) {\n        if (value > uint128(type(int128).max)) revert SafeCastOverflow();\n        return int128(uint128(value));\n    }\n\n    /// @dev Safely convert int128 to uint256\n    function toUint256(int128 value) internal pure returns (uint256) {\n        if (value < 0) revert SafeCastUnderflow();\n        return uint256(int256(value));\n    }\n}\n"},{"file_path":"contracts/musd/FeeAccrualMath.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.33;\n\nimport {IEnclaveDebtManager} from \"./IEnclaveDebtManager.sol\";\n\n/// @notice System-wide fee accumulator. The numerator is the sum of\n///         (principal_i * rate_i) across all active positions, where rate_i is\n///         an annual rate in basis points. The implicit denominator is\n///         BPS * SECONDS_IN_A_YEAR (10 000 * 31 556 952), which converts the\n///         raw basis-point-seconds product into a proper token amount.\n///         Together with lastUpdateTime, the FeeAccrualMath library can\n///         compute how much fee has accrued across every position in O(1) - a\n///         single multiplication of the numerator by elapsed time gives the\n///         aggregate, without iterating individual positions.\nstruct FeeAccrual {\n    uint256 numerator;\n    uint256 lastUpdateTime;\n}\n\n/// @title FeeAccrualMath\n/// @notice Storage library for the FeeAccrual accumulator. Designed to be\n///         used with `using FeeAccrualMath for FeeAccrual`.\nlibrary FeeAccrualMath {\n    /// @dev 365.2425 days per year.\n    uint256 public constant SECONDS_IN_A_YEAR = 31_556_952;\n    uint256 internal constant BPS = 10_000;\n\n    /// @notice Snapshot lastUpdateTime to block.timestamp and return the\n    ///         amount that accrued since the previous snapshot.\n    /// @param self The fee accumulator (modified in place).\n    /// @return The accrued fee amount.\n    function accrue(FeeAccrual storage self) internal returns (uint256) {\n        uint256 fee = accrued(self);\n        self.lastUpdateTime = block.timestamp;\n        return fee;\n    }\n\n    /// @notice View-only variant of accrue: return how much has accrued since\n    ///         the last snapshot without modifying state.\n    /// @param self The fee accumulator (read only).\n    /// @return The accrued fee amount.\n    function accrued(FeeAccrual storage self) internal view returns (uint256) {\n        if (self.numerator == 0) return 0;\n\n        return _calculate(self.numerator, self.lastUpdateTime, block.timestamp);\n    }\n\n    /// @notice Add a principal's contribution to the numerator.\n    /// @param self The fee accumulator (modified in place).\n    /// @param principal The principal amount.\n    /// @param rate Annual rate in basis points.\n    function addPrincipal(\n        FeeAccrual storage self,\n        uint256 principal,\n        uint16 rate\n    ) internal {\n        self.numerator += uint256(rate) * principal;\n    }\n\n    /// @notice Remove a principal's contribution from the numerator.\n    /// @param self The fee accumulator (modified in place).\n    /// @param principal The principal amount being removed.\n    /// @param rate Annual rate in basis points.\n    function removePrincipal(\n        FeeAccrual storage self,\n        uint256 principal,\n        uint16 rate\n    ) internal {\n        self.numerator -= uint256(rate) * principal;\n    }\n\n    // -----------------------------------------------------------------------\n    //  Internal helpers\n    // -----------------------------------------------------------------------\n\n    function _calculate(\n        uint256 numerator,\n        uint256 startTime,\n        uint256 endTime\n    ) private pure returns (uint256) {\n        uint256 timeElapsed = endTime - startTime;\n        return (timeElapsed * numerator) / (BPS * SECONDS_IN_A_YEAR);\n    }\n}\n\n/// @title PositionFeeAccrual\n/// @notice Per-position fee computation. Computes the fee accrued on a single\n///         position's principal over a time window using simple interest\n///         (principal * rate * time). Designed to be used with\n///         `using PositionFeeAccrual for Position`.\nlibrary PositionFeeAccrual {\n    /// @notice Snapshot both accrued fees into the position's stored fields\n    ///         and advance lastUpdateTimestamp to block.timestamp. Both fees\n    ///         are computed before the timestamp is updated so neither\n    ///         calculation sees a zero time window.\n    /// @param self The position (modified in place).\n    /// @return interest The interest that was added to storedInterest.\n    /// @return originatorFee The originator fee that was added to\n    ///         storedOriginatorFee.\n    function accrueFees(\n        IEnclaveDebtManager.Position storage self\n    ) internal returns (uint256 interest, uint256 originatorFee) {\n        interest = _calculateFee(self, self.interestRate, block.timestamp);\n        originatorFee = _calculateFee(\n            self,\n            self.originatorFeeRate,\n            block.timestamp\n        );\n        self.storedInterest += interest;\n        self.storedOriginatorFee += originatorFee;\n        self.lastUpdateTimestamp = block.timestamp;\n    }\n\n    /// @notice Snapshot accrued fees and then zero the stored fields.\n    ///         Used during repayment settlement where system-wide accruers\n    ///         have already minted the corresponding MUSD and the\n    ///         position-level bookkeeping can be cleared.\n    /// @param self The position (modified in place).\n    function settleFees(IEnclaveDebtManager.Position storage self) internal {\n        self.storedInterest = 0;\n        self.storedOriginatorFee = 0;\n        self.lastUpdateTimestamp = block.timestamp;\n    }\n\n    /// @notice View-only: compute the interest accrued on a position since\n    ///         its last update.\n    /// @param self The position (read only).\n    /// @return The accrued interest amount.\n    function accruedInterest(\n        IEnclaveDebtManager.Position storage self\n    ) internal view returns (uint256) {\n        return _calculateFee(self, self.interestRate, block.timestamp);\n    }\n\n    /// @notice View-only: compute the originator fee accrued on a position\n    ///         since its last update.\n    /// @param self The position (read only).\n    /// @return The accrued originator fee amount.\n    function accruedOriginatorFee(\n        IEnclaveDebtManager.Position storage self\n    ) internal view returns (uint256) {\n        return _calculateFee(self, self.originatorFeeRate, block.timestamp);\n    }\n\n    /// @notice View-only: return the total accrued interest for a position,\n    ///         combining the stored snapshot with fees accrued since the last\n    ///         update.\n    /// @param self The position (read only).\n    /// @return The total accrued interest amount.\n    function totalAccruedInterest(\n        IEnclaveDebtManager.Position storage self\n    ) internal view returns (uint256) {\n        return self.storedInterest + accruedInterest(self);\n    }\n\n    /// @notice View-only: return the total accrued originator fee for a\n    ///         position, combining the stored snapshot with fees accrued since\n    ///         the last update.\n    /// @param self The position (read only).\n    /// @return The total accrued originator fee amount.\n    function totalAccruedOriginatorFee(\n        IEnclaveDebtManager.Position storage self\n    ) internal view returns (uint256) {\n        return self.storedOriginatorFee + accruedOriginatorFee(self);\n    }\n\n    function _calculateFee(\n        IEnclaveDebtManager.Position storage self,\n        uint16 rate,\n        uint256 endTime\n    ) private view returns (uint256) {\n        uint256 principal = self.principal;\n        uint256 startTime = self.lastUpdateTimestamp;\n        if (principal == 0 || rate == 0 || endTime <= startTime) return 0;\n        uint256 timeElapsed = endTime - startTime;\n        return\n            (timeElapsed * principal * uint256(rate)) /\n            (FeeAccrualMath.BPS * FeeAccrualMath.SECONDS_IN_A_YEAR);\n    }\n}\n"},{"file_path":"contracts/musd/IEnclaveDebtManager.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.33;\n\nimport {IVotingEscrow} from \"../interfaces/IVotingEscrow.sol\";\nimport {IPriceFeed} from \"./IPriceFeed.sol\";\nimport {IMUSD} from \"./IMUSD.sol\";\n\n/// @title IEnclaveDebtManager\n/// @notice On-chain debt accounting for Enclave-managed MUSD minting.\n///         Tracks per-position debt, accrues interest, and mints/burns MUSD\n///         against veBTC collateral managed by authorized Enclaves.\ninterface IEnclaveDebtManager {\n    // -----------------------------------------------------------------------\n    //  Types\n    // -----------------------------------------------------------------------\n\n    enum Status {\n        nonExistent,\n        active,\n        closedByRepayment,\n        closedByLiquidation\n    }\n\n    struct Position {\n        uint256 principal;\n        // Bookkeeping-only snapshot of accrued interest for this position.\n        // Updated whenever the principal changes so that we  can report the\n        // correct per-position total.\n        uint256 storedInterest;\n        // Same as storedInterest, it's bookkeeping-only so that we can report\n        // the correct per-position total even if the principal changed.\n        uint256 storedOriginatorFee;\n        uint256 lastUpdateTimestamp;\n        uint16 interestRate;\n        uint16 originatorFeeRate;\n        uint256 warningCR;\n        uint256 minimumCR;\n        address enclave;\n        address borrower;\n        address originator;\n        Status status;\n        uint256[] pledgedVeBtc;\n    }\n\n    // -----------------------------------------------------------------------\n    //  Events\n    // -----------------------------------------------------------------------\n\n    /// @notice Emitted when a new position is opened and MUSD is minted.\n    /// @param positionId The caller-provided unique identifier for this\n    ///        position.\n    /// @param enclave The Enclave (msg.sender) that opened the position and\n    ///        holds the pledged veBTC.\n    /// @param borrower The address that received the minted MUSD.\n    /// @param debtAmount The amount of MUSD minted as principal.\n    /// @param originator The originator address that will receive originator\n    ///        fees for this position.\n    /// @param interestRate Annual interest rate in basis points.\n    /// @param originatorFeeRate Annual originator fee rate in basis points.\n    /// @param warningCR The position's warning collateralization ratio.\n    /// @param minimumCR The position's minimum collateralization ratio.\n    /// @param pledgedVeBtc The veBTC token IDs pledged as collateral.\n    /// @dev This event intentionally omits collateral amounts. The BTC\n    ///      locked inside each pledged veBTC token can change outside of\n    ///      this contract, so a point-in-time snapshot would be misleading.\n    //       Off-chain systems should read collateral from on-chain state via\n    ///      getPositionCollateral() and getPositionCR().\n    event PositionOpened(\n        bytes32 indexed positionId,\n        address indexed enclave,\n        address indexed borrower,\n        uint256 debtAmount,\n        address originator,\n        uint16 interestRate,\n        uint16 originatorFeeRate,\n        uint256 warningCR,\n        uint256 minimumCR,\n        uint256[] pledgedVeBtc\n    );\n\n    /// @notice Emitted when the debt of an existing position is increased.\n    /// @param positionId The position that was modified.\n    /// @param additionalDebt The amount of additional MUSD minted.\n    /// @param newPrincipal The position's new total principal after the increase.\n    /// @dev This event intentionally omits collateral amounts. The BTC\n    ///      locked inside each pledged veBTC token can change outside of\n    ///      this contract, so a point-in-time snapshot would be misleading.\n    //       Off-chain systems should read collateral from on-chain state via\n    ///      getPositionCollateral() and getPositionCR().\n    event DebtIncreased(\n        bytes32 indexed positionId,\n        uint256 additionalDebt,\n        uint256 newPrincipal\n    );\n\n    /// @notice Emitted when additional veBTC tokens are pledged to a position.\n    /// @dev This event intentionally omits collateral amounts. The BTC\n    ///      locked inside each pledged veBTC token can change outside of\n    ///      this contract, so a point-in-time snapshot would be misleading.\n    //       Off-chain systems should read collateral from on-chain state via\n    ///      getPositionCollateral() and getPositionCR().\n    /// @param positionId The position that received the new collateral.\n    /// @param tokenIdsAdded The veBTC token IDs that were pledged.\n    /// @param pledgedTokenIds The full set of pledged veBTC token IDs after the addition.\n    event PledgedVeBtcAdded(\n        bytes32 indexed positionId,\n        uint256[] tokenIdsAdded,\n        uint256[] pledgedTokenIds\n    );\n\n    /// @notice Emitted when pledged veBTC tokens are removed from a position.\n    /// @dev This event intentionally omits collateral amounts. The BTC\n    ///      locked inside each pledged veBTC token can change outside of\n    ///      this contract, so a point-in-time snapshot would be misleading.\n    //       Off-chain systems should read collateral from on-chain state via\n    ///      getPositionCollateral() and getPositionCR().\n    /// @param positionId The position that lost collateral.\n    /// @param tokenIdsRemoved The veBTC token IDs that were removed.\n    /// @param pledgedTokenIds The full set of pledged veBTC token IDs after the removal.\n    event PledgedVeBtcRemoved(\n        bytes32 indexed positionId,\n        uint256[] tokenIdsRemoved,\n        uint256[] pledgedTokenIds\n    );\n\n    /// @notice Emitted when MUSD principal is repaid (burned) on a position.\n    /// @param positionId The position that was repaid.\n    /// @param amount The amount of MUSD burned as repayment.\n    /// @param remainingPrincipal The position's principal after the repayment.\n    event DebtRepaid(\n        bytes32 indexed positionId,\n        uint256 amount,\n        uint256 remainingPrincipal\n    );\n\n    /// @notice Emitted when a position is fully repaid and closed.\n    /// @param positionId The position that was closed.\n    event PositionClosed(bytes32 indexed positionId);\n\n    /// @notice Emitted when the CR thresholds of a position are updated.\n    /// @param positionId The position whose thresholds were changed.\n    /// @param warningCR The new warning collateralization ratio.\n    /// @param minimumCR The new minimum collateralization ratio.\n    event PositionCRThresholdsSet(\n        bytes32 indexed positionId,\n        uint256 warningCR,\n        uint256 minimumCR\n    );\n\n    /// @notice Emitted when accrued system interest is materialized and minted\n    ///         to the PCV address.\n    /// @param interest The amount of MUSD minted in this call.\n    /// @param totalInterestMinted Cumulative interest minted to date.\n    event InterestAccrued(uint256 interest, uint256 totalInterestMinted);\n\n    /// @notice Emitted when accrued originator fee is materialized and minted\n    ///         to an originator address.\n    /// @param originator The originator that received the fee.\n    /// @param originatorFee The amount of MUSD minted in this call.\n    /// @param totalOriginatorFeeMinted Cumulative originator fee minted to\n    ///        date across all originators.\n    event OriginatorFeeAccrued(\n        address indexed originator,\n        uint256 originatorFee,\n        uint256 totalOriginatorFeeMinted\n    );\n\n    /// @notice Emitted when an Enclave changes a position's interest rate.\n    /// @param positionId The position whose rate was changed.\n    /// @param oldRate The previous annual interest rate in basis points.\n    /// @param newRate The new annual interest rate in basis points.\n    event PositionInterestRateSet(\n        bytes32 indexed positionId,\n        uint16 oldRate,\n        uint16 newRate\n    );\n\n    /// @notice Emitted when an Enclave changes a position's originator fee\n    ///         rate.\n    /// @param positionId The position whose rate was changed.\n    /// @param oldRate The previous annual originator fee rate in basis points.\n    /// @param newRate The new annual originator fee rate in basis points.\n    event PositionOriginatorFeeRateSet(\n        bytes32 indexed positionId,\n        uint16 oldRate,\n        uint16 newRate\n    );\n\n    /// @notice Emitted when governance updates the maximum combined rate.\n    /// @param maxRate The new maximum combined rate in basis points.\n    event MaxRateSet(uint16 maxRate);\n\n    /// @notice Emitted when governance updates the mint cap.\n    /// @param mintCap The new mint cap in MUSD.\n    event MintCapSet(uint256 mintCap);\n\n    // -----------------------------------------------------------------------\n    //  Errors\n    // -----------------------------------------------------------------------\n\n    /// @notice Thrown when a zero address is provided where one is not allowed.\n    error ZeroAddress();\n\n    /// @notice Thrown when a zero amount is provided where a positive value is\n    ///         required.\n    error ZeroAmount();\n\n    /// @notice Thrown when a zero-bytes position ID is provided.\n    error ZeroPositionId();\n\n    /// @notice Thrown when attempting to open a position with an ID that is\n    ///         already in use.\n    error PositionAlreadyExists(bytes32 positionId);\n\n    /// @notice Thrown when the pledged veBTC array is empty.\n    error EmptyPledgedVeBtc();\n\n    /// @notice Thrown when the pledged veBTC array exceeds the maximum allowed.\n    error TooManyPledgedVeBtc(uint256 count);\n\n    /// @notice Thrown when the caller does not own a pledged veBTC token.\n    error NotTokenOwner(uint256 tokenId);\n\n    /// @notice Thrown when a veBTC token is already pledged to another position.\n    error TokenAlreadyPledged(uint256 tokenId, bytes32 positionId);\n\n    /// @notice Thrown when attempting to remove a veBTC token that is not\n    ///         pledged to the given position.\n    /// @param tokenId The veBTC token ID that was not found as pledged to the\n    ///        given position.\n    /// @param positionId The position it was expected to belong to.\n    error TokenNotPledged(uint256 tokenId, bytes32 positionId);\n\n    /// @notice Thrown when attempting to modify a position that is not active.\n    error PositionNotActive(bytes32 positionId);\n\n    /// @notice Thrown when the collateralization ratio is below the position's\n    ///         minimum threshold.\n    error InsufficientCollateral(\n        bytes32 positionId,\n        uint256 cr,\n        uint256 minimumCR\n    );\n\n    /// @notice Thrown when the caller is not the enclave that owns the position.\n    error NotPositionEnclave(bytes32 positionId);\n\n    /// @notice Thrown when the repayment amount is less than the position's\n    ///         accrued fees.\n    error RepaymentInsufficientForFees(\n        bytes32 positionId,\n        uint256 amount,\n        uint256 fees\n    );\n\n    /// @notice Thrown when the repayment amount - after fee deduction -\n    ///         exceeds the position's principal.\n    error RepaymentExceedsPrincipal(\n        bytes32 positionId,\n        uint256 amount,\n        uint256 principal\n    );\n\n    /// @notice Thrown when the sum of interestRate and originatorFeeRate\n    ///         exceeds the governance-set maximum combined rate.\n    /// @param combinedRate The sum of interestRate + originatorFeeRate.\n    /// @param maxRate The current maximum allowed combined rate.\n    error RateExceedsMaxRate(uint32 combinedRate, uint16 maxRate);\n\n    /// @notice Thrown when an operation would push totalPrincipal above\n    ///         the governance-set mint cap.\n    /// @param newTotalPrincipal What totalPrincipal would become.\n    /// @param mintCap The current mint cap.\n    error MintCapExceeded(uint256 newTotalPrincipal, uint256 mintCap);\n\n    /// @notice Thrown when minimumCR is below 110% (1.1e18).\n    /// @param minimumCR The invalid minimum collateralization ratio.\n    error MinimumCRTooLow(uint256 minimumCR);\n\n    /// @notice Thrown when warningCR is not strictly above minimumCR.\n    /// @param warningCR The warning collateralization ratio.\n    /// @param minimumCR The minimum collateralization ratio.\n    error WarningCRNotAboveMinimumCR(uint256 warningCR, uint256 minimumCR);\n\n    // -----------------------------------------------------------------------\n    //  Views\n    // -----------------------------------------------------------------------\n\n    /// @notice The MUSD stablecoin contract.\n    function musd() external view returns (IMUSD);\n\n    /// @notice The veBTC (VotingEscrow) contract.\n    function veBTC() external view returns (IVotingEscrow);\n\n    /// @notice The price feed contract.\n    function priceFeed() external view returns (IPriceFeed);\n\n    /// @notice The PCV (Protocol Controlled Value) address that receives\n    ///         interest.\n    function pcv() external view returns (address);\n\n    /// @notice The maximum allowed combined rate (interestRate +\n    ///         originatorFeeRate) in basis points. Enforced when opening a\n    ///         position. A value of 0 means only zero-rate positions are\n    ///         permitted.\n    function maxRate() external view returns (uint16);\n\n    /// @notice The maximum net outstanding principal across all active\n    ///         positions. Enforced when opening a position or increasing\n    ///         debt. A value of 0 blocks all new minting (existing\n    ///         positions are unaffected). Governance may set the cap\n    ///         below the current totalPrincipal - this does not force\n    ///         liquidation but prevents new debt until repayments bring\n    ///         the total back under the cap.\n    function mintCap() external view returns (uint256);\n\n    /// @notice Sum of all active positions' principal.\n    function totalPrincipal() external view returns (uint256);\n\n    /// @notice Cumulative MUSD ever minted as principal through this contract.\n    function totalMintedDebt() external view returns (uint256);\n\n    /// @notice Cumulative MUSD principal burned through repayment.\n    function totalDebtBurned() external view returns (uint256);\n\n    /// @notice Return the full Position struct for a given position ID.\n    /// @param positionId The position identifier.\n    /// @return The Position struct (status == nonExistent if not found).\n    function getPosition(\n        bytes32 positionId\n    ) external view returns (Position memory);\n\n    /// @notice Return the position ID that a veBTC token is pledged to.\n    ///         Returns bytes32(0) if the token is not pledged.\n    /// @param tokenId The veBTC NFT token ID.\n    /// @return The position ID, or bytes32(0) if unpledged.\n    function getVeBtcPositionId(\n        uint256 tokenId\n    ) external view returns (bytes32);\n\n    /// @notice Return the pledged veBTC token IDs for a given position.\n    /// @param positionId The position identifier.\n    /// @return Array of veBTC NFT token IDs pledged to this position.\n    function getPledgedVeBtc(\n        bytes32 positionId\n    ) external view returns (uint256[] memory);\n\n    /// @notice Compute the collateral value of a position by summing the\n    ///         locked BTC amount of all pledged veBTC tokens.\n    /// @param positionId The position identifier.\n    /// @return The total collateral in BTC (1e18 = 1 BTC).\n    function getPositionCollateral(\n        bytes32 positionId\n    ) external view returns (uint256);\n\n    /// @notice Compute the collateralization ratio of a position.\n    /// @dev Returns (collateral * price) / totalDebt, scaled to 1e18.\n    ///      Returns type(uint256).max when totalDebt is zero.\n    /// @param positionId The position identifier.\n    /// @return The collateralization ratio (1.5e18 = 150%).\n    function getPositionCR(bytes32 positionId) external view returns (uint256);\n\n    /// @notice Return the full debt breakdown for a position: principal,\n    ///         accrued interest, accrued originator fee, and total debt.\n    ///         Accrued amounts include both stored snapshots and newly accrued\n    ///         since the last snapshot.\n    /// @param positionId The position identifier.\n    /// @return principal The position's principal amount.\n    /// @return accruedInterest Total accrued interest (stored + pending).\n    /// @return accruedOriginatorFee Total accrued originator fee (stored + pending).\n    /// @return totalDebt Sum of principal + accruedInterest + accruedOriginatorFee.\n    function getPositionDebt(\n        bytes32 positionId\n    )\n        external\n        view\n        returns (\n            uint256 principal,\n            uint256 accruedInterest,\n            uint256 accruedOriginatorFee,\n            uint256 totalDebt\n        );\n\n    /// @notice Return the health status of a position: its current CR,\n    ///         the warning and minimum CR thresholds, and whether it is\n    ///         below each threshold.\n    /// @param _positionId The position identifier.\n    /// @return currentCR The current collateralization ratio.\n    /// @return warningCR The position's warning CR threshold.\n    /// @return minimumCR The position's minimum CR threshold.\n    /// @return isBelowWarning True if currentCR < warningCR.\n    /// @return isBelowMinimum True if currentCR < minimumCR.\n    function getPositionHealthStatus(\n        bytes32 _positionId\n    )\n        external\n        view\n        returns (\n            uint256 currentCR,\n            uint256 warningCR,\n            uint256 minimumCR,\n            bool isBelowWarning,\n            bool isBelowMinimum\n        );\n\n    /// @notice Cumulative MUSD minted as interest through this contract.\n    function totalInterestMinted() external view returns (uint256);\n\n    /// @notice Return the interest that would be minted if\n    ///         accrueInterest() were called now.\n    /// @return The accrued but not-yet-minted interest amount.\n    function getAccruedInterest() external view returns (uint256);\n\n    /// @notice Cumulative MUSD minted as originator fee through this contract\n    ///         across all originators.\n    function totalOriginatorFeeMinted() external view returns (uint256);\n\n    /// @notice Cumulative MUSD minted as originator fee for a specific\n    ///         originator.\n    /// @param _originator The originator address.\n    /// @return The cumulative originator fee minted to this originator.\n    function originatorFeeMinted(\n        address _originator\n    ) external view returns (uint256);\n\n    /// @notice Return the originator fee that would be minted if\n    ///         accrueOriginatorFee(_originator) were called now.\n    /// @param _originator The originator address.\n    /// @return The accrued but not-yet-minted originator fee amount.\n    function getAccruedOriginatorFee(\n        address _originator\n    ) external view returns (uint256);\n\n    /// @notice Total outstanding debt across all active positions, including\n    ///         accrued but unsettled interest and originator fees.\n    /// @return The total outstanding debt in MUSD.\n    function getTotalOutstandingDebt() external view returns (uint256);\n\n    // -----------------------------------------------------------------------\n    //  Fee accrual\n    // -----------------------------------------------------------------------\n\n    /// @notice Materialize accrued interest by minting MUSD to the PCV\n    ///         address. Callable by anyone. This is a public good; it simply\n    ///         converts time-accrued interest into minted tokens.\n    function accrueInterest() external;\n\n    /// @notice Materialize accrued originator fee for a specific originator\n    ///         by minting MUSD to their address. Callable by anyone.\n    /// @param _originator The originator to materialize fees for.\n    function accrueOriginatorFee(address _originator) external;\n\n    // -----------------------------------------------------------------------\n    //  Governance\n    // -----------------------------------------------------------------------\n\n    /// @notice Pause the contract. Prevents opening positions, increasing\n    ///         debt, and accruing fees. Only callable by an address with\n    ///         PAUSER_ROLE.\n    function pause() external;\n\n    /// @notice Unpause the contract. Only callable by an address with\n    ///         GOVERNANCE_ROLE.\n    function unpause() external;\n\n    /// @notice Set the maximum allowed combined rate (interestRate +\n    ///         originatorFeeRate) in basis points. Only callable by\n    ///         governance. Enforced in openPosition. Setting to 0 permits\n    ///         only zero-rate positions. Setting to type(uint16).max\n    ///         effectively disables the cap.\n    /// @param _maxRate The new maximum combined rate.\n    function setMaxRate(uint16 _maxRate) external;\n\n    /// @notice Set the maximum net outstanding principal across all active\n    ///         positions. Only callable by governance. Enforced in\n    ///         openPosition and increaseDebt. Setting to 0 blocks all new\n    ///         minting. Setting below the current totalPrincipal is allowed\n    ///         and does not affect existing positions - new minting resumes\n    ///         once repayments bring the total under the cap. Setting to\n    ///         type(uint256).max effectively disabled the cap.\n    /// @param _cap The new mint cap in MUSD.\n    function setMintCap(uint256 _cap) external;\n\n    // -----------------------------------------------------------------------\n    //  Enclave actions\n    // -----------------------------------------------------------------------\n\n    /// @notice Open a new position and mint MUSD to the borrower.\n    ///         The caller must be an Enclave contract with ENCLAVE_ROLE. The\n    ///         Enclave must own each pledged veBTC token. Because the veBTC\n    ///         NFTs remain inside the Enclave - which enforces its own access\n    ///         control - they cannot be transferred out without authorization,\n    ///         effectively locking the collateral for the lifetime of the\n    ///         position.\n    /// @param _positionId Caller-chosen unique identifier (e.g. partner loan\n    ///        ID).\n    /// @param _borrower Address that will receive the minted MUSD.\n    /// @param _originator Address that will receive originator fees for this\n    ///        position.\n    /// @param _debtAmount Amount of MUSD to mint as principal.\n    /// @param _interestRate Annual interest rate in basis points.\n    /// @param _originatorFeeRate Annual originator fee rate in basis points.\n    /// @param _pledgedVeBtc Array of veBTC token IDs to pledge as collateral.\n    ///        The caller (Enclave) must own each token. Each token must not\n    ///        already be pledged to another position.\n    /// @param _warningCR Indicative CR threshold for off-chain margin warnings.\n    /// @param _minimumCR Indicative CR threshold for off-chain liquidation.\n    function openPosition(\n        bytes32 _positionId,\n        address _borrower,\n        address _originator,\n        uint256 _debtAmount,\n        uint16 _interestRate,\n        uint16 _originatorFeeRate,\n        uint256[] calldata _pledgedVeBtc,\n        uint256 _warningCR,\n        uint256 _minimumCR\n    ) external;\n\n    /// @notice Increase the debt of an existing active position. Mints\n    ///         additional MUSD to the borrower. Only callable by an address\n    ///         with ENCLAVE_ROLE.\n    /// @param _positionId The position to increase debt on.\n    /// @param _additionalDebt The amount of additional MUSD to mint.\n    function increaseDebt(\n        bytes32 _positionId,\n        uint256 _additionalDebt\n    ) external;\n\n    /// @notice Pledge additional veBTC tokens to an existing active\n    ///         position, improving its collateralization ratio. The caller\n    ///         must own each token and each token must not already be pledged\n    ///         to another position. Only callable by the Enclave that owns\n    ///         the position.\n    /// @param _positionId The position to add collateral to.\n    /// @param _tokenIdsToAdd Array of veBTC token IDs to add.\n    function addPledgedVeBtc(\n        bytes32 _positionId,\n        uint256[] calldata _tokenIdsToAdd\n    ) external;\n\n    /// @notice Remove pledged veBTC tokens from an existing active position.\n    ///         The position must remain above its minimumCR after removal.\n    ///         Only callable by the Enclave that owns the position.\n    /// @param _positionId The position to remove collateral from.\n    /// @param _tokenIdsToRemove Array of veBTC token IDs to remove.\n    function removePledgedVeBtc(\n        bytes32 _positionId,\n        uint256[] calldata _tokenIdsToRemove\n    ) external;\n\n    /// @notice Update the warning and minimum CR thresholds on an existing\n    ///         active position. Only callable by the Enclave that owns the\n    ///         position. The position's current CR must be at or above the\n    ///         new minimumCR.\n    /// @param _positionId The position to update.\n    /// @param _warningCR The new warning collateralization ratio. Must be\n    ///        strictly above _minimumCR.\n    /// @param _minimumCR The new minimum collateralization ratio. Must be\n    ///        strictly above MIN_MINIMUM_CR (1.1e18).\n    function setPositionCRThresholds(\n        bytes32 _positionId,\n        uint256 _warningCR,\n        uint256 _minimumCR\n    ) external;\n\n    /// @notice Repay MUSD against a position's debt. Accrues and settles\n    ///         all interest and originator fees to date. The accrued fees\n    ///         are deducted from _amount first; the remainder reduces the\n    ///         position's principal. If the full principal is repaid, the\n    ///         position is closed. Only callable by the Enclave that owns\n    ///         the position.\n    /// @dev The _amount of MUSD needs to be approved to the debt manager\n    ///      before calling this function.\n    /// @param _positionId The position to repay.\n    /// @param _amount Total MUSD to burn from msg.sender. Must be at least\n    ///        the accrued fees; the surplus reduces principal.\n    function repay(bytes32 _positionId, uint256 _amount) external;\n\n    /// @notice Repay a position's entire debt (principal plus all accrued\n    ///         interest and originator fees) computed at the current block\n    ///         timestamp, and close the position. Because the payoff is\n    ///         computed in the same transaction as the burn, the position is\n    ///         always fully closed regardless of how much interest accrued\n    ///         since the debt was last touched. Only callable by the Enclave\n    ///         that owns the position.\n    /// @dev The caller must approve the debt manager for at least the full\n    ///      debt before calling. An approval with a buffer is recommended since\n    ///      the exact amount is not known until execution; the contract burns\n    ///      only the computed payoff, never more.\n    /// @param _positionId The position to fully repay.\n    /// @return amount The total MUSD burned (principal + interest +\n    ///         originator fee).\n    function repayAll(bytes32 _positionId) external returns (uint256 amount);\n\n    /// @notice Change the annual interest rate on an active position.\n    ///         Accrues all pending fees at the old rate before switching so\n    ///         that no fees are lost or double-counted. The new combined rate\n    ///         (interestRate + originatorFeeRate) must not exceed maxRate.\n    ///         Only callable by the Enclave that owns the position.\n    /// @param _positionId The position to update.\n    /// @param _newInterestRate The new annual interest rate in basis points.\n    function setPositionInterestRate(\n        bytes32 _positionId,\n        uint16 _newInterestRate\n    ) external;\n\n    /// @notice Change the annual originator fee rate on an active position.\n    ///         Accrues all pending fees at the old rate before switching so\n    ///         that no fees are lost or double-counted. The new combined rate\n    ///         (interestRate + originatorFeeRate) must not exceed maxRate.\n    ///         Only callable by the Enclave that owns the position.\n    /// @param _positionId The position to update.\n    /// @param _newOriginatorFeeRate The new annual originator fee rate in\n    ///        basis points.\n    function setPositionOriginatorFeeRate(\n        bytes32 _positionId,\n        uint16 _newOriginatorFeeRate\n    ) external;\n}\n"},{"file_path":"contracts/musd/IMUSD.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.33;\n\n/// @notice Minimal interface for the MUSD stablecoin's mint and burn functions.\ninterface IMUSD {\n    function mint(address _account, uint256 _amount) external;\n    function burn(address _account, uint256 _amount) external;\n}\n"},{"file_path":"contracts/musd/IPriceFeed.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.33;\n\n/// @title IPriceFeed\n/// @notice Minimal interface for a BTC/USD price oracle used by the\n///         EnclaveDebtManager to compute collateralization ratios.\ninterface IPriceFeed {\n    /// @notice Return the current BTC price in USD, scaled to 1e18.\n    function fetchPrice() external view returns (uint256);\n}\n"}],"certified":false,"abi":[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"EmptyPledgedVeBtc","type":"error"},{"inputs":[{"internalType":"bytes32","name":"positionId","type":"bytes32"},{"internalType":"uint256","name":"cr","type":"uint256"},{"internalType":"uint256","name":"minimumCR","type":"uint256"}],"name":"InsufficientCollateral","type":"error"},{"inputs":[{"internalType":"uint256","name":"minimumCR","type":"uint256"}],"name":"MinimumCRTooLow","type":"error"},{"inputs":[{"internalType":"uint256","name":"newTotalPrincipal","type":"uint256"},{"internalType":"uint256","name":"mintCap","type":"uint256"}],"name":"MintCapExceeded","type":"error"},{"inputs":[{"internalType":"bytes32","name":"positionId","type":"bytes32"}],"name":"NotPositionEnclave","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"NotTokenOwner","type":"error"},{"inputs":[{"internalType":"bytes32","name":"positionId","type":"bytes32"}],"name":"PositionAlreadyExists","type":"error"},{"inputs":[{"internalType":"bytes32","name":"positionId","type":"bytes32"}],"name":"PositionNotActive","type":"error"},{"inputs":[{"internalType":"uint32","name":"combinedRate","type":"uint32"},{"internalType":"uint16","name":"maxRate","type":"uint16"}],"name":"RateExceedsMaxRate","type":"error"},{"inputs":[{"internalType":"bytes32","name":"positionId","type":"bytes32"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"principal","type":"uint256"}],"name":"RepaymentExceedsPrincipal","type":"error"},{"inputs":[{"internalType":"bytes32","name":"positionId","type":"bytes32"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"fees","type":"uint256"}],"name":"RepaymentInsufficientForFees","type":"error"},{"inputs":[],"name":"SafeCastUnderflow","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes32","name":"positionId","type":"bytes32"}],"name":"TokenAlreadyPledged","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes32","name":"positionId","type":"bytes32"}],"name":"TokenNotPledged","type":"error"},{"inputs":[{"internalType":"uint256","name":"count","type":"uint256"}],"name":"TooManyPledgedVeBtc","type":"error"},{"inputs":[{"internalType":"uint256","name":"warningCR","type":"uint256"},{"internalType":"uint256","name":"minimumCR","type":"uint256"}],"name":"WarningCRNotAboveMinimumCR","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"ZeroAmount","type":"error"},{"inputs":[],"name":"ZeroPositionId","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"positionId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"additionalDebt","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newPrincipal","type":"uint256"}],"name":"DebtIncreased","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"positionId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"remainingPrincipal","type":"uint256"}],"name":"DebtRepaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"interest","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalInterestMinted","type":"uint256"}],"name":"InterestAccrued","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"maxRate","type":"uint16"}],"name":"MaxRateSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"mintCap","type":"uint256"}],"name":"MintCapSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"originator","type":"address"},{"indexed":false,"internalType":"uint256","name":"originatorFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalOriginatorFeeMinted","type":"uint256"}],"name":"OriginatorFeeAccrued","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"positionId","type":"bytes32"},{"indexed":false,"internalType":"uint256[]","name":"tokenIdsAdded","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"pledgedTokenIds","type":"uint256[]"}],"name":"PledgedVeBtcAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"positionId","type":"bytes32"},{"indexed":false,"internalType":"uint256[]","name":"tokenIdsRemoved","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"pledgedTokenIds","type":"uint256[]"}],"name":"PledgedVeBtcRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"positionId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"warningCR","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"minimumCR","type":"uint256"}],"name":"PositionCRThresholdsSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"positionId","type":"bytes32"}],"name":"PositionClosed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"positionId","type":"bytes32"},{"indexed":false,"internalType":"uint16","name":"oldRate","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"newRate","type":"uint16"}],"name":"PositionInterestRateSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"positionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"enclave","type":"address"},{"indexed":true,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"debtAmount","type":"uint256"},{"indexed":false,"internalType":"address","name":"originator","type":"address"},{"indexed":false,"internalType":"uint16","name":"interestRate","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"originatorFeeRate","type":"uint16"},{"indexed":false,"internalType":"uint256","name":"warningCR","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"minimumCR","type":"uint256"},{"indexed":false,"internalType":"uint256[]","name":"pledgedVeBtc","type":"uint256[]"}],"name":"PositionOpened","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"positionId","type":"bytes32"},{"indexed":false,"internalType":"uint16","name":"oldRate","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"newRate","type":"uint16"}],"name":"PositionOriginatorFeeRateSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ENCLAVE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GOVERNANCE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_PLEDGED_VEBTC","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_MINIMUM_CR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PAUSER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accrueInterest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_originator","type":"address"}],"name":"accrueOriginatorFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_positionId","type":"bytes32"},{"internalType":"uint256[]","name":"_tokenIdsToAdd","type":"uint256[]"}],"name":"addPledgedVeBtc","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"combinedFees","outputs":[{"internalType":"uint256","name":"numerator","type":"uint256"},{"internalType":"uint256","name":"lastUpdateTime","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAccruedInterest","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_originator","type":"address"}],"name":"getAccruedOriginatorFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"positionId","type":"bytes32"}],"name":"getPledgedVeBtc","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"positionId","type":"bytes32"}],"name":"getPosition","outputs":[{"components":[{"internalType":"uint256","name":"principal","type":"uint256"},{"internalType":"uint256","name":"storedInterest","type":"uint256"},{"internalType":"uint256","name":"storedOriginatorFee","type":"uint256"},{"internalType":"uint256","name":"lastUpdateTimestamp","type":"uint256"},{"internalType":"uint16","name":"interestRate","type":"uint16"},{"internalType":"uint16","name":"originatorFeeRate","type":"uint16"},{"internalType":"uint256","name":"warningCR","type":"uint256"},{"internalType":"uint256","name":"minimumCR","type":"uint256"},{"internalType":"address","name":"enclave","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"address","name":"originator","type":"address"},{"internalType":"enum IEnclaveDebtManager.Status","name":"status","type":"uint8"},{"internalType":"uint256[]","name":"pledgedVeBtc","type":"uint256[]"}],"internalType":"struct IEnclaveDebtManager.Position","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"positionId","type":"bytes32"}],"name":"getPositionCR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"positionId","type":"bytes32"}],"name":"getPositionCollateral","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"positionId","type":"bytes32"}],"name":"getPositionDebt","outputs":[{"internalType":"uint256","name":"principal","type":"uint256"},{"internalType":"uint256","name":"accruedInterest","type":"uint256"},{"internalType":"uint256","name":"accruedOriginatorFee","type":"uint256"},{"internalType":"uint256","name":"totalDebt","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_positionId","type":"bytes32"}],"name":"getPositionHealthStatus","outputs":[{"internalType":"uint256","name":"currentCR","type":"uint256"},{"internalType":"uint256","name":"warningCR","type":"uint256"},{"internalType":"uint256","name":"minimumCR","type":"uint256"},{"internalType":"bool","name":"isBelowWarning","type":"bool"},{"internalType":"bool","name":"isBelowMinimum","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalOutstandingDebt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getVeBtcPositionId","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_positionId","type":"bytes32"},{"internalType":"uint256","name":"_additionalDebt","type":"uint256"}],"name":"increaseDebt","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_musd","type":"address"},{"internalType":"address","name":"_veBTC","type":"address"},{"internalType":"address","name":"_priceFeed","type":"address"},{"internalType":"address","name":"_governance","type":"address"},{"internalType":"address","name":"_pauser","type":"address"},{"internalType":"address","name":"_pcv","type":"address"},{"internalType":"address[]","name":"_enclaves","type":"address[]"},{"internalType":"uint16","name":"_maxRate","type":"uint16"},{"internalType":"uint256","name":"_mintCap","type":"uint256"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"interest","outputs":[{"internalType":"uint256","name":"numerator","type":"uint256"},{"internalType":"uint256","name":"lastUpdateTime","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxRate","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mintCap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"musd","outputs":[{"internalType":"contract IMUSD","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_positionId","type":"bytes32"},{"internalType":"address","name":"_borrower","type":"address"},{"internalType":"address","name":"_originator","type":"address"},{"internalType":"uint256","name":"_debtAmount","type":"uint256"},{"internalType":"uint16","name":"_interestRate","type":"uint16"},{"internalType":"uint16","name":"_originatorFeeRate","type":"uint16"},{"internalType":"uint256[]","name":"_pledgedVeBtcIds","type":"uint256[]"},{"internalType":"uint256","name":"_warningCR","type":"uint256"},{"internalType":"uint256","name":"_minimumCR","type":"uint256"}],"name":"openPosition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"originatorFeeMinted","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"originatorFees","outputs":[{"internalType":"uint256","name":"numerator","type":"uint256"},{"internalType":"uint256","name":"lastUpdateTime","type":"uint256"}],"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":"pcv","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceFeed","outputs":[{"internalType":"contract IPriceFeed","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_positionId","type":"bytes32"},{"internalType":"uint256[]","name":"_tokenIdsToRemove","type":"uint256[]"}],"name":"removePledgedVeBtc","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_positionId","type":"bytes32"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"repay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_positionId","type":"bytes32"}],"name":"repayAll","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_maxRate","type":"uint16"}],"name":"setMaxRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_cap","type":"uint256"}],"name":"setMintCap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_positionId","type":"bytes32"},{"internalType":"uint256","name":"_warningCR","type":"uint256"},{"internalType":"uint256","name":"_minimumCR","type":"uint256"}],"name":"setPositionCRThresholds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_positionId","type":"bytes32"},{"internalType":"uint16","name":"_newInterestRate","type":"uint16"}],"name":"setPositionInterestRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_positionId","type":"bytes32"},{"internalType":"uint16","name":"_newOriginatorFeeRate","type":"uint16"}],"name":"setPositionOriginatorFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalDebtBurned","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalFeeSettled","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalFeesStored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalInterestMinted","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalMintedDebt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalOriginatorFeeMinted","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalPrincipal","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"veBTC","outputs":[{"internalType":"contract IVotingEscrow","name":"","type":"address"}],"stateMutability":"view","type":"function"}],"is_changed_bytecode":false,"is_partially_verified":false,"constructor_args":null}