creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "contracts/SyncedLiquidationSequencer.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.17;\n\nimport \"./Interfaces/IPriceFeed.sol\";\nimport \"./Interfaces/ICdpManager.sol\";\nimport \"./Interfaces/ISortedCdps.sol\";\nimport \"./Interfaces/ICdpManagerData.sol\";\nimport \"./Dependencies/EbtcBase.sol\";\n\n/// @notice Helper to turn a sequence into CDP id array for batch liquidation\ncontract SyncedLiquidationSequencer is EbtcBase {\n    ICdpManager public immutable cdpManager;\n    ISortedCdps public immutable sortedCdps;\n\n    /// @param _cdpManagerAddress Address of CdpManager contract\n    /// @param _sortedCdpsAddress Address of SortedCdps contract\n    /// @param _priceFeedAddress Address of price feed\n    /// @param _activePoolAddress Address of ActivePool\n    /// @param _collateralAddress Address of collateral contract\n    constructor(\n        address _cdpManagerAddress,\n        address _sortedCdpsAddress,\n        address _priceFeedAddress,\n        address _activePoolAddress,\n        address _collateralAddress\n    ) EbtcBase(_activePoolAddress, _priceFeedAddress, _collateralAddress) {\n        cdpManager = ICdpManager(_cdpManagerAddress);\n        sortedCdps = ISortedCdps(_sortedCdpsAddress);\n    }\n\n    /// @notice Get first N batch of liquidatable Cdps at current price, starting at lowest ICR\n    /// @dev Non-view function that updates and returns live price at execution time\n    /// @param _n Number of Cdps to retrieve\n    /// @return _array Array of CDP IDs to batch liquidate\n    function sequenceLiqToBatchLiq(uint256 _n) external returns (bytes32[] memory _array) {\n        uint256 _price = priceFeed.fetchPrice();\n        return sequenceLiqToBatchLiqWithPrice(_n, _price);\n    }\n\n    /// @notice Get first N batch of liquidatable Cdps at specified price, starting at lowest ICR\n    /// @param _n Number of Cdps to retrieve\n    /// @param _price stETH/BTC price\n    /// @return _array Array of CDP IDs\n    function sequenceLiqToBatchLiqWithPrice(\n        uint256 _n,\n        uint256 _price\n    ) public view returns (bytes32[] memory _array) {\n        (uint256 _TCR, , ) = _getTCRWithSystemDebtAndCollShares(_price);\n        bool _recoveryModeAtStart = _TCR < CCR ? true : false;\n        return _sequenceLiqToBatchLiq(_n, _recoveryModeAtStart, _price);\n    }\n\n    /// @notice Returns array of liquidatable CDP ids\n    /// @param _n Number of Cdps to retrieve\n    /// @param _recoveryModeAtStart Initial recovery mode state\n    /// @param _price stETH/BTC price\n    /// @return _array Array of CDP IDs for batch liquidation (in NICR-decreasing order, same as SortedCdps)\n    function _sequenceLiqToBatchLiq(\n        uint256 _n,\n        bool _recoveryModeAtStart,\n        uint256 _price\n    ) internal view returns (bytes32[] memory _array) {\n        if (_n > 0) {\n            bytes32 _last = sortedCdps.getLast();\n            bytes32 _first = sortedCdps.getFirst();\n            bytes32 _cdpId = _last;\n\n            uint256 _TCR = cdpManager.getSyncedTCR(_price);\n\n            // get count of liquidatable Cdps\n            uint256 _cnt;\n            for (uint256 i = 0; i < _n && _cdpId != _first; ++i) {\n                uint256 _icr = cdpManager.getSyncedICR(_cdpId, _price); /// @audit This is view ICR and not real ICR\n                uint256 _cdpStatus = cdpManager.getCdpStatus(_cdpId);\n                bool _liquidatable = _canLiquidateInCurrentMode(_recoveryModeAtStart, _icr, _TCR);\n                if (_liquidatable && _cdpStatus == 1) {\n                    _cnt += 1;\n                }\n                _cdpId = sortedCdps.getPrev(_cdpId);\n            }\n\n            // retrieve liquidatable Cdps\n            _array = new bytes32[](_cnt);\n            _cdpId = _last;\n            uint256 _j;\n            for (uint256 i = 0; i < _n && _cdpId != _first; ++i) {\n                uint256 _icr = cdpManager.getSyncedICR(_cdpId, _price);\n                uint256 _cdpStatus = cdpManager.getCdpStatus(_cdpId);\n                bool _liquidatable = _canLiquidateInCurrentMode(_recoveryModeAtStart, _icr, _TCR);\n                if (_liquidatable && _cdpStatus == 1) {\n                    // 1 = ICdpManagerData.Status.active\n                    _array[_cnt - _j - 1] = _cdpId;\n                    _j += 1;\n                }\n                _cdpId = sortedCdps.getPrev(_cdpId);\n            }\n            require(_j == _cnt, \"LiquidationLibrary: wrong sequence conversion!\");\n        }\n    }\n\n    /// @notice Internal helper function to check if given ICR value can be liquidated in current mode\n    /// @dev Assumes correct input values\n    /// @param _recovery Current recovery mode state\n    /// @param _icr CDP's current ICR\n    /// @param _TCR Current total system collateralization ratio\n    /// @return True if liquidatable\n    function _canLiquidateInCurrentMode(\n        bool _recovery,\n        uint256 _icr,\n        uint256 _TCR\n    ) internal view returns (bool) {\n        bool _liquidatable = _recovery ? (_icr < MCR || _icr <= _TCR) : _icr < MCR;\n\n        return _liquidatable;\n    }\n}\n"
      },
      "contracts/Interfaces/IPriceFeed.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.17;\n\ninterface IPriceFeed {\n    // --- Events ---\n    event LastGoodPriceUpdated(uint256 _lastGoodPrice);\n    event PriceFeedStatusChanged(Status newStatus);\n    event FallbackCallerChanged(\n        address indexed _oldFallbackCaller,\n        address indexed _newFallbackCaller\n    );\n    event UnhealthyFallbackCaller(address indexed _fallbackCaller, uint256 timestamp);\n    event CollateralFeedSourceUpdated(address indexed stEthFeed);\n\n    // --- Structs ---\n\n    struct ChainlinkResponse {\n        uint80 roundEthBtcId;\n        uint80 roundStEthEthId;\n        uint256 answer;\n        uint256 timestampEthBtc;\n        uint256 timestampStEthEth;\n        bool success;\n    }\n\n    struct FallbackResponse {\n        uint256 answer;\n        uint256 timestamp;\n        bool success;\n    }\n\n    // --- Enum ---\n\n    enum Status {\n        chainlinkWorking,\n        usingFallbackChainlinkUntrusted,\n        bothOraclesUntrusted,\n        usingFallbackChainlinkFrozen,\n        usingChainlinkFallbackUntrusted\n    }\n\n    // --- Function ---\n    function fetchPrice() external returns (uint256);\n}\n"
      },
      "contracts/Interfaces/ICdpManager.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.17;\n\nimport \"./IEbtcBase.sol\";\nimport \"./ICdpManagerData.sol\";\n\n// Common interface for the Cdp Manager.\ninterface ICdpManager is IEbtcBase, ICdpManagerData {\n    // --- Functions ---\n    function liquidate(bytes32 _cdpId) external;\n\n    function partiallyLiquidate(\n        bytes32 _cdpId,\n        uint256 _partialAmount,\n        bytes32 _upperPartialHint,\n        bytes32 _lowerPartialHint\n    ) external;\n\n    function batchLiquidateCdps(bytes32[] calldata _cdpArray) external;\n\n    function redeemCollateral(\n        uint256 _EBTCAmount,\n        bytes32 _firstRedemptionHint,\n        bytes32 _upperPartialRedemptionHint,\n        bytes32 _lowerPartialRedemptionHint,\n        uint256 _partialRedemptionHintNICR,\n        uint256 _maxIterations,\n        uint256 _maxFee\n    ) external;\n\n    function updateStakeAndTotalStakes(bytes32 _cdpId) external returns (uint256);\n\n    function syncAccounting(bytes32 _cdpId) external;\n\n    function closeCdp(bytes32 _cdpId, address _borrower, uint256 _debt, uint256 _coll) external;\n\n    function getRedemptionRate() external view returns (uint256);\n\n    function getRedemptionRateWithDecay() external view returns (uint256);\n\n    function getRedemptionFeeWithDecay(uint256 _stETHToRedeem) external view returns (uint256);\n\n    function getCdpStatus(bytes32 _cdpId) external view returns (uint256);\n\n    function getCdpStake(bytes32 _cdpId) external view returns (uint256);\n\n    function getCdpDebt(bytes32 _cdpId) external view returns (uint256);\n\n    function getCdpCollShares(bytes32 _cdpId) external view returns (uint256);\n\n    function getCdpLiquidatorRewardShares(bytes32 _cdpId) external view returns (uint);\n\n    function initializeCdp(\n        bytes32 _cdpId,\n        uint256 _debt,\n        uint256 _coll,\n        uint256 _liquidatorRewardShares,\n        address _borrower\n    ) external;\n\n    function updateCdp(\n        bytes32 _cdpId,\n        address _borrower,\n        uint256 _coll,\n        uint256 _debt,\n        uint256 _newColl,\n        uint256 _newDebt\n    ) external;\n\n    function getCachedTCR(uint256 _price) external view returns (uint256);\n\n    function checkRecoveryMode(uint256 _price) external view returns (bool);\n}\n"
      },
      "contracts/Interfaces/ISortedCdps.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.17;\n\n// Common interface for the SortedCdps Doubly Linked List.\ninterface ISortedCdps {\n    // --- Events ---\n\n    event NodeAdded(bytes32 _id, uint _NICR);\n    event NodeRemoved(bytes32 _id);\n\n    // --- Functions ---\n\n    function remove(bytes32 _id) external;\n\n    function batchRemove(bytes32[] memory _ids) external;\n\n    function reInsert(bytes32 _id, uint256 _newICR, bytes32 _prevId, bytes32 _nextId) external;\n\n    function contains(bytes32 _id) external view returns (bool);\n\n    function isFull() external view returns (bool);\n\n    function isEmpty() external view returns (bool);\n\n    function getSize() external view returns (uint256);\n\n    function getMaxSize() external view returns (uint256);\n\n    function getFirst() external view returns (bytes32);\n\n    function getLast() external view returns (bytes32);\n\n    function getNext(bytes32 _id) external view returns (bytes32);\n\n    function getPrev(bytes32 _id) external view returns (bytes32);\n\n    function validInsertPosition(\n        uint256 _ICR,\n        bytes32 _prevId,\n        bytes32 _nextId\n    ) external view returns (bool);\n\n    function findInsertPosition(\n        uint256 _ICR,\n        bytes32 _prevId,\n        bytes32 _nextId\n    ) external view returns (bytes32, bytes32);\n\n    function insert(\n        address owner,\n        uint256 _ICR,\n        bytes32 _prevId,\n        bytes32 _nextId\n    ) external returns (bytes32);\n\n    function getOwnerAddress(bytes32 _id) external pure returns (address);\n\n    function nonExistId() external view returns (bytes32);\n\n    function cdpCountOf(address owner) external view returns (uint256);\n\n    function getCdpCountOf(\n        address owner,\n        bytes32 startNodeId,\n        uint maxNodes\n    ) external view returns (uint256, bytes32);\n\n    function getCdpsOf(address owner) external view returns (bytes32[] memory);\n\n    function getAllCdpsOf(\n        address owner,\n        bytes32 startNodeId,\n        uint maxNodes\n    ) external view returns (bytes32[] memory, uint256, bytes32);\n\n    function cdpOfOwnerByIndex(address owner, uint256 index) external view returns (bytes32);\n\n    function cdpOfOwnerByIdx(\n        address owner,\n        uint256 index,\n        bytes32 startNodeId,\n        uint maxNodes\n    ) external view returns (bytes32, bool);\n\n    function toCdpId(\n        address owner,\n        uint256 blockHeight,\n        uint256 nonce\n    ) external pure returns (bytes32);\n\n    function nextCdpNonce() external view returns (uint256);\n}\n"
      },
      "contracts/Interfaces/ICdpManagerData.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.17;\n\nimport \"./ICollSurplusPool.sol\";\nimport \"./IEBTCToken.sol\";\nimport \"./ISortedCdps.sol\";\nimport \"./IActivePool.sol\";\nimport \"./IRecoveryModeGracePeriod.sol\";\nimport \"../Dependencies/ICollateralTokenOracle.sol\";\n\n// Common interface for the Cdp Manager.\ninterface ICdpManagerData is IRecoveryModeGracePeriod {\n    // --- Events ---\n\n    event StakingRewardSplitSet(uint256 _stakingRewardSplit);\n    event RedemptionFeeFloorSet(uint256 _redemptionFeeFloor);\n    event MinuteDecayFactorSet(uint256 _minuteDecayFactor);\n    event BetaSet(uint256 _beta);\n    event RedemptionsPaused(bool _paused);\n\n    event Liquidation(uint256 _liquidatedDebt, uint256 _liquidatedColl, uint256 _liqReward);\n    event Redemption(\n        uint256 _debtToRedeemExpected,\n        uint256 _debtToRedeemActual,\n        uint256 _collSharesSent,\n        uint256 _feeCollShares,\n        address indexed _redeemer\n    );\n    event CdpUpdated(\n        bytes32 indexed _cdpId,\n        address indexed _borrower,\n        address indexed _executor,\n        uint256 _oldDebt,\n        uint256 _oldCollShares,\n        uint256 _debt,\n        uint256 _collShares,\n        uint256 _stake,\n        CdpOperation _operation\n    );\n    event CdpLiquidated(\n        bytes32 indexed _cdpId,\n        address indexed _borrower,\n        uint _debt,\n        uint _collShares,\n        CdpOperation _operation,\n        address indexed _liquidator,\n        uint _premiumToLiquidator\n    );\n    event CdpPartiallyLiquidated(\n        bytes32 indexed _cdpId,\n        address indexed _borrower,\n        uint256 _debt,\n        uint256 _collShares,\n        CdpOperation operation,\n        address indexed _liquidator,\n        uint _premiumToLiquidator\n    );\n    event BaseRateUpdated(uint256 _baseRate);\n    event LastRedemptionTimestampUpdated(uint256 _lastFeeOpTime);\n    event TotalStakesUpdated(uint256 _newTotalStakes);\n    event SystemSnapshotsUpdated(uint256 _totalStakesSnapshot, uint256 _totalCollateralSnapshot);\n    event SystemDebtRedistributionIndexUpdated(uint256 _systemDebtRedistributionIndex);\n    event CdpDebtRedistributionIndexUpdated(bytes32 _cdpId, uint256 _cdpDebtRedistributionIndex);\n    event CdpArrayIndexUpdated(bytes32 _cdpId, uint256 _newIndex);\n    event StEthIndexUpdated(uint256 _oldIndex, uint256 _newIndex, uint256 _updTimestamp);\n    event CollateralFeePerUnitUpdated(uint256 _oldPerUnit, uint256 _newPerUnit, uint256 _feeTaken);\n    event CdpFeeSplitApplied(\n        bytes32 _cdpId,\n        uint256 _oldPerUnitCdp,\n        uint256 _newPerUnitCdp,\n        uint256 _collReduced,\n        uint256 _collLeft\n    );\n\n    enum CdpOperation {\n        openCdp,\n        closeCdp,\n        adjustCdp,\n        syncAccounting,\n        liquidateInNormalMode,\n        liquidateInRecoveryMode,\n        redeemCollateral,\n        partiallyLiquidate,\n        failedPartialRedemption\n    }\n\n    enum Status {\n        nonExistent,\n        active,\n        closedByOwner,\n        closedByLiquidation,\n        closedByRedemption\n    }\n\n    // Store the necessary data for a cdp\n    struct Cdp {\n        uint256 debt;\n        uint256 coll;\n        uint256 stake;\n        uint128 liquidatorRewardShares;\n        Status status;\n    }\n\n    /*\n     * --- Variable container structs for liquidations ---\n     *\n     * These structs are used to hold, return and assign variables inside the liquidation functions,\n     * in order to avoid the error: \"CompilerError: Stack too deep\".\n     **/\n\n    struct CdpDebtAndCollShares {\n        uint256 debt;\n        uint256 collShares;\n    }\n\n    struct LiquidationLocals {\n        bytes32 cdpId;\n        uint256 partialAmount; // used only for partial liquidation, default 0 means full liquidation\n        uint256 price;\n        uint256 ICR;\n        bytes32 upperPartialHint;\n        bytes32 lowerPartialHint;\n        bool recoveryModeAtStart;\n        uint256 TCR;\n        uint256 totalSurplusCollShares;\n        uint256 totalCollSharesToSend;\n        uint256 totalDebtToBurn;\n        uint256 totalDebtToRedistribute;\n        uint256 totalLiquidatorRewardCollShares;\n    }\n\n    struct LiquidationRecoveryModeLocals {\n        uint256 entireSystemDebt;\n        uint256 entireSystemColl;\n        uint256 totalDebtToBurn;\n        uint256 totalCollSharesToSend;\n        uint256 totalSurplusCollShares;\n        bytes32 cdpId;\n        uint256 price;\n        uint256 ICR;\n        uint256 totalDebtToRedistribute;\n        uint256 totalLiquidatorRewardCollShares;\n    }\n\n    struct LocalVariables_OuterLiquidationFunction {\n        uint256 price;\n        bool recoveryModeAtStart;\n        uint256 liquidatedDebt;\n        uint256 liquidatedColl;\n    }\n\n    struct LocalVariables_LiquidationSequence {\n        uint256 i;\n        uint256 ICR;\n        bytes32 cdpId;\n        bool backToNormalMode;\n        uint256 entireSystemDebt;\n        uint256 entireSystemColl;\n        uint256 price;\n        uint256 TCR;\n    }\n\n    struct SingleRedemptionInputs {\n        bytes32 cdpId;\n        uint256 maxEBTCamount;\n        uint256 price;\n        bytes32 upperPartialRedemptionHint;\n        bytes32 lowerPartialRedemptionHint;\n        uint256 partialRedemptionHintNICR;\n    }\n\n    struct LiquidationValues {\n        uint256 entireCdpDebt;\n        uint256 debtToBurn;\n        uint256 totalCollToSendToLiquidator;\n        uint256 debtToRedistribute;\n        uint256 collSurplus;\n        uint256 liquidatorCollSharesReward;\n    }\n\n    struct LiquidationTotals {\n        uint256 totalDebtInSequence;\n        uint256 totalDebtToBurn;\n        uint256 totalCollToSendToLiquidator;\n        uint256 totalDebtToRedistribute;\n        uint256 totalCollSurplus;\n        uint256 totalCollReward;\n    }\n\n    // --- Variable container structs for redemptions ---\n\n    struct RedemptionTotals {\n        uint256 remainingDebtToRedeem;\n        uint256 debtToRedeem;\n        uint256 collSharesDrawn;\n        uint256 totalCollSharesSurplus;\n        uint256 feeCollShares;\n        uint256 collSharesToRedeemer;\n        uint256 decayedBaseRate;\n        uint256 price;\n        uint256 systemDebtAtStart;\n        uint256 twapSystemDebtAtStart;\n        uint256 systemCollSharesAtStart;\n        uint256 tcrAtStart;\n    }\n\n    struct SingleRedemptionValues {\n        uint256 debtToRedeem;\n        uint256 collSharesDrawn;\n        uint256 collSurplus;\n        uint256 liquidatorRewardShares;\n        bool cancelledPartial;\n        bool fullRedemption;\n        uint256 newPartialNICR;\n    }\n\n    function getActiveCdpsCount() external view returns (uint256);\n\n    function totalStakes() external view returns (uint256);\n\n    function ebtcToken() external view returns (IEBTCToken);\n\n    function systemStEthFeePerUnitIndex() external view returns (uint256);\n\n    function systemStEthFeePerUnitIndexError() external view returns (uint256);\n\n    function stEthIndex() external view returns (uint256);\n\n    function calcFeeUponStakingReward(\n        uint256 _newIndex,\n        uint256 _prevIndex\n    ) external view returns (uint256, uint256, uint256);\n\n    function syncGlobalAccounting() external; // Accrues StEthFeeSplit without influencing Grace Period\n\n    function syncGlobalAccountingAndGracePeriod() external; // Accrues StEthFeeSplit and influences Grace Period\n\n    function getAccumulatedFeeSplitApplied(\n        bytes32 _cdpId,\n        uint256 _systemStEthFeePerUnitIndex\n    ) external view returns (uint256, uint256);\n\n    function getCachedNominalICR(bytes32 _cdpId) external view returns (uint256);\n\n    function getCachedICR(bytes32 _cdpId, uint256 _price) external view returns (uint256);\n\n    function getSyncedCdpDebt(bytes32 _cdpId) external view returns (uint256);\n\n    function getSyncedCdpCollShares(bytes32 _cdpId) external view returns (uint256);\n\n    function getSyncedICR(bytes32 _cdpId, uint256 _price) external view returns (uint256);\n\n    function getSyncedTCR(uint256 _price) external view returns (uint256);\n\n    function getSyncedSystemCollShares() external view returns (uint256);\n\n    function getSyncedNominalICR(bytes32 _cdpId) external view returns (uint256);\n\n    function getPendingRedistributedDebt(bytes32 _cdpId) external view returns (uint256);\n\n    function hasPendingRedistributedDebt(bytes32 _cdpId) external view returns (bool);\n\n    function getSyncedDebtAndCollShares(\n        bytes32 _cdpId\n    ) external view returns (uint256 debt, uint256 collShares);\n\n    function canLiquidateRecoveryMode(uint256 icr, uint256 tcr) external view returns (bool);\n\n    function totalCollateralSnapshot() external view returns (uint256);\n\n    function totalStakesSnapshot() external view returns (uint256);\n}\n"
      },
      "contracts/Dependencies/EbtcBase.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.17;\n\nimport \"./BaseMath.sol\";\nimport \"./EbtcMath.sol\";\nimport \"../Interfaces/IActivePool.sol\";\nimport \"../Interfaces/IPriceFeed.sol\";\nimport \"../Interfaces/IEbtcBase.sol\";\nimport \"../Dependencies/ICollateralToken.sol\";\n\n/*\n * Base contract for CdpManager, BorrowerOperations. Contains global system constants and\n * common functions.\n */\ncontract EbtcBase is BaseMath, IEbtcBase {\n    // Collateral Ratio applied for Liquidation Incentive\n    // i.e., liquidator repay $1 worth of debt to get back $1.03 worth of collateral\n    uint256 public constant LICR = 1030000000000000000; // 103%\n\n    // Minimum collateral ratio for individual cdps\n    uint256 public constant MCR = 1100000000000000000; // 110%\n\n    // Critical system collateral ratio. If the system's total collateral ratio (TCR) falls below the CCR, Recovery Mode is triggered.\n    uint256 public constant CCR = 1250000000000000000; // 125%\n\n    // Amount of stETH collateral to be locked in active pool on opening cdps\n    uint256 public constant LIQUIDATOR_REWARD = 2e17;\n\n    // Minimum amount of stETH collateral a CDP must have\n    uint256 public constant MIN_NET_STETH_BALANCE = 2e18;\n\n    uint256 public constant PERCENT_DIVISOR = 200; // dividing by 200 yields 0.5%\n\n    uint256 public constant BORROWING_FEE_FLOOR = 0; // 0.5%\n\n    uint256 public constant STAKING_REWARD_SPLIT = 5_000; // taking 50% cut from staking reward\n\n    uint256 public constant MAX_REWARD_SPLIT = 10_000;\n\n    uint256 public constant MIN_CHANGE = 1000;\n\n    IActivePool public immutable activePool;\n\n    IPriceFeed public immutable override priceFeed;\n\n    // the only collateral token allowed in CDP\n    ICollateralToken public immutable collateral;\n\n    /// @notice Initializes the contract with the provided addresses\n    /// @param _activePoolAddress The address of the ActivePool contract\n    /// @param _priceFeedAddress The address of the PriceFeed contract\n    /// @param _collateralAddress The address of the CollateralToken contract\n    constructor(address _activePoolAddress, address _priceFeedAddress, address _collateralAddress) {\n        activePool = IActivePool(_activePoolAddress);\n        priceFeed = IPriceFeed(_priceFeedAddress);\n        collateral = ICollateralToken(_collateralAddress);\n    }\n\n    // --- Gas compensation functions ---\n\n    function _calcNetStEthBalance(uint256 _stEthBalance) internal pure returns (uint256) {\n        return _stEthBalance - LIQUIDATOR_REWARD;\n    }\n\n    /// @notice Get the entire system collateral\n    /// @notice Entire system collateral = collateral allocated to system in ActivePool, using it's internal accounting\n    /// @dev Collateral tokens stored in ActivePool for liquidator rewards, fees, or coll in CollSurplusPool, are not included\n    function getSystemCollShares() public view returns (uint256 entireSystemColl) {\n        return (activePool.getSystemCollShares());\n    }\n\n    /**\n        @notice Get the entire system debt\n        @notice Entire system collateral = collateral stored in ActivePool, using their internal accounting\n     */\n    function _getSystemDebt() internal view returns (uint256 entireSystemDebt) {\n        return (activePool.getSystemDebt());\n    }\n\n    function _getCachedTCR(uint256 _price) internal view returns (uint256 TCR) {\n        (TCR, , ) = _getTCRWithSystemDebtAndCollShares(_price);\n    }\n\n    function _getTCRWithSystemDebtAndCollShares(\n        uint256 _price\n    ) internal view returns (uint256 TCR, uint256 _coll, uint256 _debt) {\n        uint256 systemCollShares = getSystemCollShares();\n        uint256 systemDebt = _getSystemDebt();\n\n        uint256 _systemStEthBalance = collateral.getPooledEthByShares(systemCollShares);\n        TCR = EbtcMath._computeCR(_systemStEthBalance, systemDebt, _price);\n\n        return (TCR, systemCollShares, systemDebt);\n    }\n\n    function _checkRecoveryMode(uint256 _price) internal view returns (bool) {\n        return _checkRecoveryModeForTCR(_getCachedTCR(_price));\n    }\n\n    function _checkRecoveryModeForTCR(uint256 _tcr) internal view returns (bool) {\n        return _tcr < CCR;\n    }\n\n    function _requireUserAcceptsFee(\n        uint256 _fee,\n        uint256 _amount,\n        uint256 _maxFeePercentage\n    ) internal pure {\n        uint256 feePercentage = (_fee * DECIMAL_PRECISION) / _amount;\n        require(feePercentage <= _maxFeePercentage, \"Fee exceeded provided maximum\");\n    }\n\n    // Convert debt denominated in ETH to debt denominated in BTC given that _price is ETH/BTC\n    // _debt is denominated in ETH\n    // _price is ETH/BTC\n    function _convertDebtDenominationToBtc(\n        uint256 _debt,\n        uint256 _price\n    ) internal pure returns (uint256) {\n        return (_debt * _price) / DECIMAL_PRECISION;\n    }\n\n    /// @dev return true if given ICR is qualified for liquidation compared to configured threshold\n    /// @dev this function ONLY checks numbers not check grace period switch for Recovery Mode\n    function _checkICRAgainstLiqThreshold(uint256 _icr, uint _tcr) internal view returns (bool) {\n        // Either undercollateralized\n        // OR, it's RM AND they meet the requirement\n        // Swapped Requirement && RM to save gas\n        return\n            _checkICRAgainstMCR(_icr) ||\n            (_checkICRAgainstTCR(_icr, _tcr) && _checkRecoveryModeForTCR(_tcr));\n    }\n\n    /// @dev return true if given ICR is qualified for liquidation compared to MCR\n    function _checkICRAgainstMCR(uint256 _icr) internal view returns (bool) {\n        return _icr < MCR;\n    }\n\n    /// @dev return true if given ICR is qualified for liquidation compared to TCR\n    /// @dev typically used in Recovery Mode\n    function _checkICRAgainstTCR(uint256 _icr, uint _tcr) internal view returns (bool) {\n        /// @audit is _icr <= _tcr more dangerous for overal system safety?\n        /// @audit Should we use _icr < CCR to allow any risky CDP being liquidated?\n        return _icr <= _tcr;\n    }\n}\n"
      },
      "contracts/Interfaces/IEbtcBase.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.17;\n\nimport \"./IPriceFeed.sol\";\n\ninterface IEbtcBase {\n    function priceFeed() external view returns (IPriceFeed);\n}\n"
      },
      "contracts/Interfaces/ICollSurplusPool.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.17;\n\ninterface ICollSurplusPool {\n    // --- Events ---\n\n    event SurplusCollSharesAdded(\n        bytes32 indexed _cdpId,\n        address indexed _account,\n        uint256 _claimableSurplusCollShares,\n        uint256 _surplusCollSharesAddedFromCollateral,\n        uint256 _surplusCollSharesAddedFromLiquidatorReward\n    );\n    event CollSharesTransferred(address indexed _to, uint256 _amount);\n\n    event SweepTokenSuccess(address indexed _token, uint256 _amount, address indexed _recipient);\n\n    // --- Contract setters ---\n\n    function getTotalSurplusCollShares() external view returns (uint256);\n\n    function getSurplusCollShares(address _account) external view returns (uint256);\n\n    function increaseSurplusCollShares(\n        bytes32 _cdpId,\n        address _account,\n        uint256 _collateralShares,\n        uint256 _liquidatorRewardShares\n    ) external;\n\n    function claimSurplusCollShares(address _account) external;\n\n    function increaseTotalSurplusCollShares(uint256 _value) external;\n}\n"
      },
      "contracts/Interfaces/IEBTCToken.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.17;\n\nimport \"../Dependencies/IERC20.sol\";\nimport \"../Dependencies/IERC2612.sol\";\n\ninterface IEBTCToken is IERC20, IERC2612 {\n    // --- Functions ---\n\n    function mint(address _account, uint256 _amount) external;\n\n    function burn(address _account, uint256 _amount) external;\n}\n"
      },
      "contracts/Interfaces/IActivePool.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.17;\n\nimport \"./IPool.sol\";\nimport \"./ITwapWeightedObserver.sol\";\n\ninterface IActivePool is IPool, ITwapWeightedObserver {\n    // --- Events ---\n    event ActivePoolEBTCDebtUpdated(uint256 _EBTCDebt);\n    event SystemCollSharesUpdated(uint256 _coll);\n    event FeeRecipientClaimableCollSharesIncreased(uint256 _coll, uint256 _fee);\n    event FeeRecipientClaimableCollSharesDecreased(uint256 _coll, uint256 _fee);\n    event FlashLoanSuccess(\n        address indexed _receiver,\n        address indexed _token,\n        uint256 _amount,\n        uint256 _fee\n    );\n    event SweepTokenSuccess(address indexed _token, uint256 _amount, address indexed _recipient);\n\n    // --- Functions ---\n    function transferSystemCollShares(address _account, uint256 _amount) external;\n\n    function increaseSystemCollShares(uint256 _value) external;\n\n    function transferSystemCollSharesAndLiquidatorReward(\n        address _account,\n        uint256 _shares,\n        uint256 _liquidatorRewardShares\n    ) external;\n\n    function allocateSystemCollSharesToFeeRecipient(uint256 _shares) external;\n\n    function claimFeeRecipientCollShares(uint256 _shares) external;\n\n    function feeRecipientAddress() external view returns (address);\n\n    function getFeeRecipientClaimableCollShares() external view returns (uint256);\n}\n"
      },
      "contracts/Interfaces/IRecoveryModeGracePeriod.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.17;\n\n// Interface for State Updates that can trigger RM Liquidations\ninterface IRecoveryModeGracePeriod {\n    event TCRNotified(uint256 TCR); /// NOTE: Mostly for debugging to ensure synch\n\n    // NOTE: Ts is implicit in events (it's added by GETH)\n    event GracePeriodStart();\n    event GracePeriodEnd();\n    event GracePeriodDurationSet(uint256 _recoveryModeGracePeriodDuration);\n\n    function notifyStartGracePeriod(uint256 tcr) external;\n\n    function notifyEndGracePeriod(uint256 tcr) external;\n}\n"
      },
      "contracts/Dependencies/ICollateralTokenOracle.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.17;\n\n/**\n * Based on the stETH:\n *  -   https://docs.lido.fi/contracts/lido#\n */\ninterface ICollateralTokenOracle {\n    // Return beacon specification data.\n    function getBeaconSpec()\n        external\n        view\n        returns (\n            uint64 epochsPerFrame,\n            uint64 slotsPerEpoch,\n            uint64 secondsPerSlot,\n            uint64 genesisTime\n        );\n}\n"
      },
      "contracts/Dependencies/BaseMath.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.17;\n\ncontract BaseMath {\n    uint256 public constant DECIMAL_PRECISION = 1e18;\n}\n"
      },
      "contracts/Dependencies/EbtcMath.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.17;\n\nlibrary EbtcMath {\n    uint256 internal constant DECIMAL_PRECISION = 1e18;\n    uint256 public constant MAX_TCR = type(uint256).max;\n\n    /* Precision for Nominal ICR (independent of price). Rationale for the value:\n     *\n     * - Making it “too high” could lead to overflows.\n     * - Making it “too low” could lead to an ICR equal to zero, due to truncation from Solidity floor division.\n     *\n     * This value of 1e20 is chosen for safety: the NICR will only overflow for numerator > ~1e39 ETH,\n     * and will only truncate to 0 if the denominator is at least 1e20 times greater than the numerator.\n     *\n     */\n    uint256 internal constant NICR_PRECISION = 1e20;\n\n    function _min(uint256 _a, uint256 _b) internal pure returns (uint256) {\n        return (_a < _b) ? _a : _b;\n    }\n\n    function _max(uint256 _a, uint256 _b) internal pure returns (uint256) {\n        return (_a >= _b) ? _a : _b;\n    }\n\n    /**\n     * credit to OpenZeppelin\n     * @dev Returns the downcasted uint128 from uint256, reverting on\n     * overflow (when the input is greater than largest uint128).\n     *\n     * Counterpart to Solidity's `uint128` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 128 bits\n     */\n    function toUint128(uint256 value) internal pure returns (uint128) {\n        require(value <= type(uint128).max, \"EbtcMath: downcast to uint128 will overflow\");\n        return uint128(value);\n    }\n\n    /*\n     * Multiply two decimal numbers and use normal rounding rules:\n     * -round product up if 19'th mantissa digit >= 5\n     * -round product down if 19'th mantissa digit < 5\n     *\n     * Used only inside the exponentiation, _decPow().\n     */\n    function decMul(uint256 x, uint256 y) internal pure returns (uint256 decProd) {\n        uint256 prod_xy = x * y;\n\n        decProd = (prod_xy + (DECIMAL_PRECISION / 2)) / DECIMAL_PRECISION;\n    }\n\n    /*\n     * _decPow: Exponentiation function for 18-digit decimal base, and integer exponent n.\n     *\n     * Uses the efficient \"exponentiation by squaring\" algorithm. O(log(n)) complexity.\n     *\n     * Called by two functions that represent time in units of minutes:\n     * 1) CdpManager._calcDecayedBaseRate\n     * 2) CommunityIssuance._getCumulativeIssuanceFraction\n     *\n     * The exponent is capped to avoid reverting due to overflow. The cap 525600000 equals\n     * \"minutes in 1000 years\": 60 * 24 * 365 * 1000\n     *\n     * If a period of > 1000 years is ever used as an exponent in either of the above functions, the result will be\n     * negligibly different from just passing the cap, since:\n     *\n     * In function 1), the decayed base rate will be 0 for 1000 years or > 1000 years\n     * In function 2), the difference in tokens issued at 1000 years and any time > 1000 years, will be negligible\n     */\n    function _decPow(uint256 _base, uint256 _minutes) internal pure returns (uint256) {\n        if (_minutes > 525600000) {\n            _minutes = 525600000;\n        } // cap to avoid overflow\n\n        if (_minutes == 0) {\n            return DECIMAL_PRECISION;\n        }\n\n        uint256 y = DECIMAL_PRECISION;\n        uint256 x = _base;\n        uint256 n = _minutes;\n\n        // Exponentiation-by-squaring\n        while (n > 1) {\n            if (n % 2 == 0) {\n                x = decMul(x, x);\n                n = n / 2;\n            } else {\n                // if (n % 2 != 0)\n                y = decMul(x, y);\n                x = decMul(x, x);\n                n = (n - 1) / 2;\n            }\n        }\n\n        return decMul(x, y);\n    }\n\n    function _getAbsoluteDifference(uint256 _a, uint256 _b) internal pure returns (uint256) {\n        return (_a >= _b) ? (_a - _b) : (_b - _a);\n    }\n\n    function _computeNominalCR(uint256 _collShares, uint256 _debt) internal pure returns (uint256) {\n        if (_debt > 0) {\n            return (_collShares * NICR_PRECISION) / _debt;\n        }\n        // Return the maximal value for uint256 if the Cdp has a debt of 0. Represents \"infinite\" CR.\n        else {\n            // if (_debt == 0)\n            return MAX_TCR;\n        }\n    }\n\n    /// @dev Compute collateralization ratio, given stETH balance, price, and debt balance\n    function _computeCR(\n        uint256 _stEthBalance,\n        uint256 _debt,\n        uint256 _price\n    ) internal pure returns (uint256) {\n        if (_debt > 0) {\n            uint256 newCollRatio = (_stEthBalance * _price) / _debt;\n\n            return newCollRatio;\n        }\n        // Return the maximal value for uint256 if the Cdp has a debt of 0. Represents \"infinite\" CR.\n        else {\n            // if (_debt == 0)\n            return MAX_TCR;\n        }\n    }\n}\n"
      },
      "contracts/Dependencies/ICollateralToken.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.17;\n\nimport \"./IERC20.sol\";\n\n/**\n * Based on the stETH:\n *  -   https://docs.lido.fi/contracts/lido#\n */\ninterface ICollateralToken is IERC20 {\n    // Returns the amount of shares that corresponds to _ethAmount protocol-controlled Ether\n    function getSharesByPooledEth(uint256 _ethAmount) external view returns (uint256);\n\n    // Returns the amount of Ether that corresponds to _sharesAmount token shares\n    function getPooledEthByShares(uint256 _sharesAmount) external view returns (uint256);\n\n    // Moves `_sharesAmount` token shares from the caller's account to the `_recipient` account.\n    function transferShares(address _recipient, uint256 _sharesAmount) external returns (uint256);\n\n    // Returns the amount of shares owned by _account\n    function sharesOf(address _account) external view returns (uint256);\n\n    // Returns authorized oracle address\n    function getOracle() external view returns (address);\n}\n"
      },
      "contracts/Dependencies/IERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.17;\n\n/**\n * Based on the OpenZeppelin IER20 interface:\n * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol\n *\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n    /**\n     * @dev Returns the amount of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the amount of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves `amount` tokens from the caller's account to `recipient`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address recipient, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    function increaseAllowance(address spender, uint256 addedValue) external returns (bool);\n\n    function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool);\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Moves `amount` tokens from `sender` to `recipient` using the\n     * allowance mechanism. `amount` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);\n\n    function name() external view returns (string memory);\n\n    function symbol() external view returns (string memory);\n\n    function decimals() external view returns (uint8);\n\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n"
      },
      "contracts/Dependencies/IERC2612.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.17;\n\n/**\n * @dev Interface of the ERC2612 standard as defined in the EIP.\n *\n * Adds the {permit} method, which can be used to change one's\n * {IERC20-allowance} without having to send a transaction, by signing a\n * message. This allows users to spend tokens without having to hold Ether.\n *\n * See https://eips.ethereum.org/EIPS/eip-2612.\n *\n * Code adapted from https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2237/\n */\ninterface IERC2612 {\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over `owner`'s tokens,\n     * given `owner`'s signed approval.\n     *\n     * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n     * ordering also apply here.\n     *\n     * Emits an {Approval} event.\n     *\n     * Requirements:\n     *\n     * - `owner` cannot be the zero address.\n     * - `spender` cannot be the zero address.\n     * - `deadline` must be a timestamp in the future.\n     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n     * over the EIP712-formatted function arguments.\n     * - the signature must use ``owner``'s current nonce (see {nonces}).\n     *\n     * For more information on the signature format, see the\n     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n     * section].\n     */\n    function permit(\n        address owner,\n        address spender,\n        uint256 amount,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external;\n\n    /**\n     * @dev Returns the current ERC2612 nonce for `owner`. This value must be\n     * included whenever a signature is generated for {permit}.\n     *\n     * Every successful call to {permit} increases `owner`'s nonce by one. This\n     * prevents a signature from being used multiple times.\n     *\n     * `owner` can limit the time a Permit is valid for by setting `deadline` to\n     * a value in the near future. The deadline argument can be set to uint256(-1) to\n     * create Permits that effectively never expire.\n     */\n    function nonces(address owner) external view returns (uint256);\n\n    function version() external view returns (string memory);\n\n    function permitTypeHash() external view returns (bytes32);\n\n    function domainSeparator() external view returns (bytes32);\n}\n"
      },
      "contracts/Interfaces/IPool.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.17;\n\n// Common interface for the Pools.\ninterface IPool {\n    // --- Events ---\n\n    event ETHBalanceUpdated(uint256 _newBalance);\n    event EBTCBalanceUpdated(uint256 _newBalance);\n    event CollSharesTransferred(address indexed _to, uint256 _amount);\n\n    // --- Functions ---\n\n    function getSystemCollShares() external view returns (uint256);\n\n    function getSystemDebt() external view returns (uint256);\n\n    function increaseSystemDebt(uint256 _amount) external;\n\n    function decreaseSystemDebt(uint256 _amount) external;\n}\n"
      },
      "contracts/Interfaces/ITwapWeightedObserver.sol": {
        "content": "// SPDX-License Identifier: MIT\npragma solidity 0.8.17;\nimport {IBaseTwapWeightedObserver} from \"./IBaseTwapWeightedObserver.sol\";\n\ninterface ITwapWeightedObserver is IBaseTwapWeightedObserver {\n    event TwapDisabled();\n\n    function PERIOD() external view returns (uint256);\n\n    function valueToTrack() external view returns (uint128);\n\n    function timeToAccrue() external view returns (uint64);\n\n    function getLatestAccumulator() external view returns (uint128);\n\n    function observe() external returns (uint256);\n\n    function update() external;\n\n    function twapDisabled() external view returns (bool);\n}\n"
      },
      "contracts/Interfaces/IBaseTwapWeightedObserver.sol": {
        "content": "// SPDX-License Identifier: MIT\npragma solidity 0.8.17;\n\ninterface IBaseTwapWeightedObserver {\n    // NOTE: Packing manually is cheaper, but this is simpler to understand and follow\n    struct PackedData {\n        // Slot 0\n        // Seconds in a year: 3.154e+7\n        /// @dev Accumulator value recorded for TWAP Observer until last update\n        uint128 observerCumuVal; // 3.154e+7 * 80 * 100e27 = 2.5232e+38 | log_2(100e27 * 3.154e+7 * 80) = 127.568522171\n        /// @dev Accumulator for TWAP globally\n        uint128 accumulator; // 3.154e+7 * 80 * 100e27 = 2.5232e+38 | log_2(100e27 * 3.154e+7 * 80) = 127.568522171\n        // NOTE: We can further compress this slot but we will not be able to use only one (see u72 impl)\n        /// So what's the point of making the code more complex?\n\n        // Slot 1\n        /// @dev last update timestamp for TWAP Observer\n        uint64 lastObserved; // Thousands of Years, if we use relative time we can use u32 | Relative to deploy time (as immutable)\n        /// @dev last update timestamp for TWAP global track(spot) value\n        uint64 lastAccrued; // Thousands of years\n        // Expect eBTC debt to never surpass 100e27, which is 100 BILLION eBTC\n        // log_2(100e27) = 96.3359147517 | log_2(100e27 / 1e18) = 36.5412090438\n        // We could use a u64\n        /// @dev average value since last observe\n        uint128 lastObservedAverage;\n    }\n}\n"
      }
    },
    "settings": {
      "remappings": [
        "ds-test/=lib/forge-std/lib/ds-test/src/",
        "forge-std/=lib/forge-std/src/",
        "@crytic/properties/=node_modules/@crytic/properties/",
        "@openzeppelin/=node_modules/@openzeppelin/",
        "@ensdomains/=node_modules/@ensdomains/",
        "ERC4626/=lib/properties/lib/ERC4626/contracts/",
        "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
        "eth-gas-reporter/=node_modules/eth-gas-reporter/",
        "hardhat/=node_modules/hardhat/",
        "openzeppelin-contracts/=lib/openzeppelin-contracts/",
        "openzeppelin/=lib/openzeppelin-contracts/contracts/",
        "properties/=lib/properties/contracts/",
        "solmate/=node_modules/solmate/"
      ],
      "optimizer": {
        "enabled": true,
        "runs": 200
      },
      "metadata": {
        "useLiteralContent": false,
        "bytecodeHash": "ipfs"
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "evmVersion": "london",
      "libraries": {}
    }
  }}