{"file_path":"contracts/MintingHubV3/MintingHub.sol","creation_status":"success","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IDecentralizedEURO} from \"../interface/IDecentralizedEURO.sol\";\nimport {IERC20Metadata} from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {ILeadrate} from \"../interface/ILeadrate.sol\";\nimport {IReserve} from \"../interface/IReserve.sol\";\nimport {IMintingHub} from \"./interface/IMintingHub.sol\";\nimport {IPositionFactory} from \"./interface/IPositionFactory.sol\";\nimport {IPosition} from \"./interface/IPosition.sol\";\nimport {IWrappedNative} from \"../interface/IWrappedNative.sol\";\nimport {Leadrate} from \"../Leadrate.sol\";\nimport {ERC165} from \"@openzeppelin/contracts/utils/introspection/ERC165.sol\";\nimport {Ownable} from \"@openzeppelin/contracts/access/Ownable.sol\";\nimport {PositionRoller} from \"./PositionRoller.sol\";\n\n/**\n * @title Minting Hub\n * @notice The central hub for creating, cloning, and challenging collateralized DecentralizedEURO positions.\n * @dev Only one instance of this contract is required, whereas every new position comes with a new position\n * contract. Pending challenges are stored as structs in an array.\n *\n * Unsupported collateral token types (enforced via governance):\n * - Fee-on-transfer tokens: break collateral accounting (actual balance < recorded amount)\n * - Rebasing tokens: break challenge accounting (challengedAmount becomes stale after rebase)\n */\ncontract MintingHub is IMintingHub, ERC165, Leadrate {\n    /**\n     * @notice Irrevocable fee in deur when proposing a new position (but not when cloning an existing one).\n     */\n    uint256 public constant OPENING_FEE = 1000 * 10 ** 18;\n\n    /**\n     * @notice The challenger reward in parts per million (ppm) relative to the challenged amount, whereas\n     * challenged amount is defined as the challenged collateral amount times the liquidation price.\n     */\n    uint256 public constant CHALLENGER_REWARD = 20000; // 2%\n    uint256 public constant EXPIRED_PRICE_FACTOR = 10;\n\n    IPositionFactory private immutable POSITION_FACTORY; // position contract to clone\n\n    IDecentralizedEURO public immutable DEURO; // currency\n    address public immutable WETH; // wrapped native token\n    PositionRoller public immutable ROLLER; // helper to roll positions\n    Challenge[] public challenges; // list of open challenges\n\n    /**\n     * @notice Map to remember pending postponed collateral returns.\n     * @dev It maps collateral => beneficiary => amount.\n     */\n    mapping(address collateral => mapping(address owner => uint256 amount)) public pendingReturns;\n\n    struct Challenge {\n        address challenger; // the address from which the challenge was initiated\n        uint40 start; // the start of the challenge\n        IPosition position; // the position that was challenged\n        uint256 size; // how much collateral the challenger provided\n    }\n\n    event PositionOpened(address indexed owner, address indexed position, address original, address collateral);\n    event ChallengeStarted(address indexed challenger, address indexed position, uint256 size, uint256 number);\n    event ChallengeAverted(address indexed position, uint256 number, uint256 size);\n    event ChallengeSucceeded(\n        address indexed position,\n        uint256 number,\n        uint256 bid,\n        uint256 acquiredCollateral,\n        uint256 challengeSize\n    );\n    event PostponedReturn(address collateral, address indexed beneficiary, uint256 amount);\n    event ForcedSale(address pos, uint256 amount, uint256 priceE36MinusDecimals);\n\n    error UnexpectedPrice();\n    error InvalidPos();\n    error IncompatibleCollateral();\n    error InsufficientCollateral();\n    error LeaveNoDust(uint256 amount);\n    error InvalidRiskPremium();\n    error InvalidReservePPM();\n    error InvalidCollateralDecimals();\n    error ChallengeTimeTooShort();\n    error InitPeriodTooShort();\n    error NativeOnlyForWETH();\n    error ValueMismatch();\n    error NativeTransferFailed();\n\n    modifier validPos(address position) {\n        if (DEURO.getPositionParent(position) != address(this)) revert InvalidPos();\n        _;\n    }\n\n    constructor(address _deur, uint24 _initialRatePPM, address payable _roller, address _factory, address _weth)\n        Leadrate(IReserve(IDecentralizedEURO(_deur).reserve()), _initialRatePPM)\n    {\n        DEURO = IDecentralizedEURO(_deur);\n        POSITION_FACTORY = IPositionFactory(_factory);\n        WETH = _weth;\n        ROLLER = PositionRoller(_roller);\n    }\n\n    function RATE() public view returns (ILeadrate) {\n        return ILeadrate(address(this));\n    }\n\n    // Events for centralized position monitoring\n    function emitPositionUpdate(uint256 _collateral, uint256 _price, uint256 _principal) external validPos(msg.sender) {\n        emit PositionUpdate(msg.sender, _collateral, _price, _principal);\n    }\n\n    function emitPositionDenied(address denier, string calldata message) external validPos(msg.sender) {\n        emit PositionDeniedByGovernance(msg.sender, denier, message);\n    }\n\n    /**\n     * @notice Open a collateralized loan position. See also https://docs.dEURO.com/positions/open .\n     * @dev For a successful call, you must set an allowance for the collateral token, allowing\n     * the minting hub to transfer the initial collateral amount to the newly created position and to\n     * withdraw the fees.\n     *\n     * @param _collateralAddress  address of collateral token\n     * @param _minCollateral      minimum collateral required to prevent dust amounts\n     * @param _initialCollateral  amount of initial collateral to be deposited\n     * @param _mintingMaximum     maximal amount of deur that can be minted by the position owner\n     * @param _initPeriodSeconds  initial period in seconds\n     * @param _expirationSeconds  position tenor in seconds from 'now'\n     * @param _challengeSeconds   challenge period. Longer for less liquid collateral.\n     * @param _riskPremium        ppm of minted amount that is added to the applicable minting fee as a risk premium\n     * @param _liqPrice           Liquidation price with (36 - token decimals) decimals,\n     *                            e.g. 18 decimals for an 18 dec collateral, 36 decs for a 0 dec collateral.\n     * @param _reservePPM         ppm of minted amount that is locked as borrower's reserve, e.g. 20%\n     * @return address            address of created position\n     */\n    function openPosition(\n        address _collateralAddress,\n        uint256 _minCollateral,\n        uint256 _initialCollateral,\n        uint256 _mintingMaximum,\n        uint40 _initPeriodSeconds,\n        uint40 _expirationSeconds,\n        uint40 _challengeSeconds,\n        uint24 _riskPremium,\n        uint256 _liqPrice,\n        uint24 _reservePPM\n    ) public payable returns (address) {\n        {\n            if (_riskPremium > 1_000_000) revert InvalidRiskPremium();\n            if (CHALLENGER_REWARD > _reservePPM || _reservePPM > 1_000_000) revert InvalidReservePPM();\n            if (IERC20Metadata(_collateralAddress).decimals() > 24) revert InvalidCollateralDecimals(); // leaves 12 digits for price\n            if (_challengeSeconds < 1 days) revert ChallengeTimeTooShort();\n            if (_initPeriodSeconds < 3 days) revert InitPeriodTooShort();\n            uint256 invalidAmount = IERC20(_collateralAddress).totalSupply() + 1;\n            // TODO: Improve for older tokens that revert with assert,\n            // which consumes all gas and makes the entire tx fail (uncatchable)\n            try IERC20(_collateralAddress).transfer(address(0x123), invalidAmount) {\n                revert IncompatibleCollateral(); // we need a collateral that reverts on failed transfers\n            } catch Error(string memory /*reason*/) {} catch Panic(uint /*errorCode*/) {} catch (\n                bytes memory /*lowLevelData*/\n            ) {}\n            if (_initialCollateral < _minCollateral) revert InsufficientCollateral();\n            // must start with at least 500 deur worth of collateral\n            if (_minCollateral * _liqPrice < 500 ether * 10 ** 18) revert InsufficientCollateral();\n        }\n        IPosition pos = IPosition(\n            POSITION_FACTORY.createNewPosition(\n                msg.sender,\n                address(DEURO),\n                _collateralAddress,\n                _minCollateral,\n                _mintingMaximum,\n                _initPeriodSeconds,\n                _expirationSeconds,\n                _challengeSeconds,\n                _riskPremium,\n                _liqPrice,\n                _reservePPM\n            )\n        );\n        DEURO.registerPosition(address(pos));\n        DEURO.collectProfits(msg.sender, OPENING_FEE);\n        if (msg.value > 0) {\n            if (_collateralAddress != WETH) revert NativeOnlyForWETH();\n            if (msg.value != _initialCollateral) revert ValueMismatch();\n            IWrappedNative(WETH).deposit{value: msg.value}();\n            IERC20(WETH).transfer(address(pos), _initialCollateral);\n        } else {\n            IERC20(_collateralAddress).transferFrom(msg.sender, address(pos), _initialCollateral);\n        }\n\n        emit PositionOpened(msg.sender, address(pos), address(pos), _collateralAddress);\n        return address(pos);\n    }\n\n    /**\n     * @notice Clones an existing position and immediately tries to mint the specified amount using the given collateral.\n     * @dev This needs an allowance to be set on the collateral contract such that the minting hub can get the collateral.\n     * @param _liqPrice If non-zero, adjusts the liquidation price before transferring ownership (enables single-tx custom price).\n     */\n    function clone(\n        address owner,\n        address parent,\n        uint256 _initialCollateral,\n        uint256 _initialMint,\n        uint40 expiration,\n        uint256 _liqPrice\n    ) public payable validPos(parent) returns (address) {\n        address pos = POSITION_FACTORY.clonePosition(parent);\n        IPosition child = IPosition(pos);\n        child.initialize(parent, expiration);\n        DEURO.registerPosition(pos);\n        IERC20 collateral = child.collateral();\n        if (_initialCollateral < child.minimumCollateral()) revert InsufficientCollateral();\n        if (msg.value > 0) {\n            if (address(collateral) != WETH) revert NativeOnlyForWETH();\n            if (msg.value != _initialCollateral) revert ValueMismatch();\n            IWrappedNative(WETH).deposit{value: msg.value}();\n            collateral.transfer(pos, _initialCollateral);\n        } else {\n            collateral.transferFrom(msg.sender, pos, _initialCollateral);\n        }\n        emit PositionOpened(owner, address(pos), parent, address(collateral));\n        child.mint(owner, _initialMint);\n        if (_liqPrice > 0 && _liqPrice != child.price()) {\n            child.adjustPrice(_liqPrice);\n        }\n        Ownable(address(child)).transferOwnership(owner);\n        return address(pos);\n    }\n\n    /**\n     * @notice Launch a challenge (Dutch auction) on a position\n     * @param _positionAddr address of the position we want to challenge\n     * @param _collateralAmount amount of the collateral we want to challenge\n     * @param minimumPrice guards against the minter front-running with a price change\n     * @return index of the challenge in the challenge-array\n     */\n    function challenge(\n        address _positionAddr,\n        uint256 _collateralAmount,\n        uint256 minimumPrice\n    ) external payable validPos(_positionAddr) returns (uint256) {\n        IPosition position = IPosition(_positionAddr);\n        // challenger should be ok if front-run by owner with a higher price\n        // in case owner front-runs challenger with small price decrease to prevent challenge,\n        // the challenger should set minimumPrice to market price\n        uint256 liqPrice = position.virtualPrice();\n        if (liqPrice < minimumPrice) revert UnexpectedPrice();\n        address collateralAddr = address(position.collateral());\n        if (msg.value > 0) {\n            if (collateralAddr != WETH) revert NativeOnlyForWETH();\n            if (msg.value != _collateralAmount) revert ValueMismatch();\n            IWrappedNative(WETH).deposit{value: msg.value}();\n        } else {\n            IERC20(collateralAddr).transferFrom(msg.sender, address(this), _collateralAmount);\n        }\n        uint256 pos = challenges.length;\n        challenges.push(Challenge(msg.sender, uint40(block.timestamp), position, _collateralAmount));\n        position.notifyChallengeStarted(_collateralAmount, liqPrice);\n        emit ChallengeStarted(msg.sender, address(position), _collateralAmount, pos);\n        return pos;\n    }\n\n    /**\n     * @notice Post a bid in deur given an open challenge.\n     *\n     * @dev In case that the collateral cannot be transferred back to the challenger (i.e. because the collateral token\n     * has a blacklist and the challenger is on it), it is possible to postpone the return of the collateral.\n     *\n     * @param _challengeNumber          index of the challenge as broadcast in the event\n     * @param size                      how much of the collateral the caller wants to bid for at most\n     *                                  (automatically reduced to the available amount)\n     * @param postponeCollateralReturn  To postpone the return of the collateral to the challenger. Usually false.\n     */\n    function bid(uint256 _challengeNumber, uint256 size, bool postponeCollateralReturn, bool returnCollateralAsNative) external {\n        _bid(_challengeNumber, size, postponeCollateralReturn, returnCollateralAsNative);\n    }\n\n    /**\n     * @notice Post a bid in deur given an open challenge (backward compatible).\n     */\n    function bid(uint256 _challengeNumber, uint256 size, bool postponeCollateralReturn) external {\n        _bid(_challengeNumber, size, postponeCollateralReturn, false);\n    }\n\n    function _bid(uint256 _challengeNumber, uint256 size, bool postponeCollateralReturn, bool returnCollateralAsNative) internal {\n        Challenge memory _challenge = challenges[_challengeNumber];\n        (uint256 liqPrice, uint40 phase) = _challenge.position.challengeData();\n        size = _challenge.size < size ? _challenge.size : size; // cannot bid for more than the size of the challenge\n\n        if (block.timestamp <= _challenge.start + phase) {\n            _avertChallenge(_challenge, _challengeNumber, liqPrice, size, returnCollateralAsNative);\n            emit ChallengeAverted(address(_challenge.position), _challengeNumber, size);\n        } else {\n            _returnChallengerCollateral(_challenge, _challengeNumber, size, postponeCollateralReturn, returnCollateralAsNative);\n            (uint256 transferredCollateral, uint256 offer) = _finishChallenge(_challenge, size, returnCollateralAsNative);\n            emit ChallengeSucceeded(address(_challenge.position), _challengeNumber, offer, transferredCollateral, size);\n        }\n    }\n\n    function _finishChallenge(\n        Challenge memory _challenge,\n        uint256 size,\n        bool asNative\n    ) internal returns (uint256, uint256) {\n        uint256 unitPrice = _challengeUnitPrice(_challenge);\n\n        // Repayments depend on what was actually minted, whereas bids depend on the available collateral\n        (address owner, uint256 collateral, uint256 repayment, uint256 interest, uint32 reservePPM) = _challenge\n            .position\n            .notifyChallengeSucceeded(size);\n\n        // No overflow possible thanks to invariant (col * price <= limit * 10**18)\n        // enforced in Position.setPrice and knowing that collateral <= col.\n        uint256 offer = (unitPrice * collateral) / 10 ** 18;\n\n        DEURO.transferFrom(msg.sender, address(this), offer); // get money from bidder\n        uint256 reward = (offer * CHALLENGER_REWARD) / 1_000_000;\n        DEURO.transfer(_challenge.challenger, reward); // pay out the challenger reward\n        uint256 fundsAvailable = offer - reward; // funds available after reward\n\n        if (fundsAvailable > repayment + interest) {\n            uint256 profits = (reservePPM * (fundsAvailable - repayment - interest)) / 1_000_000;\n            DEURO.collectProfits(address(this), profits);\n            DEURO.transfer(owner, fundsAvailable - repayment - interest - profits);\n        } else if (fundsAvailable < repayment + interest) {\n            DEURO.coverLoss(address(this), repayment + interest - fundsAvailable); // ensure we have enough to pay everything\n        }\n        DEURO.burnWithoutReserve(repayment, reservePPM);\n        DEURO.collectProfits(address(this), interest);\n        if (asNative && address(_challenge.position.collateral()) == WETH) {\n            _challenge.position.transferChallengedCollateral(address(this), collateral);\n            IWrappedNative(WETH).withdraw(collateral);\n            (bool success, ) = msg.sender.call{value: collateral}(\"\");\n            if (!success) revert NativeTransferFailed();\n        } else {\n            _challenge.position.transferChallengedCollateral(msg.sender, collateral);\n        }\n        return (collateral, offer);\n    }\n\n    function _avertChallenge(Challenge memory _challenge, uint256 number, uint256 liqPrice, uint256 size, bool asNative) internal {\n        require(block.timestamp != _challenge.start); // do not allow to avert the challenge in the same transaction, see CS-ZCHF-037\n        if (msg.sender == _challenge.challenger) {\n            // allow challenger to cancel challenge without paying themselves\n        } else {\n            DEURO.transferFrom(msg.sender, _challenge.challenger, (size * liqPrice) / (10 ** 18));\n        }\n\n        _challenge.position.notifyChallengeAverted(size);\n        if (size < _challenge.size) {\n            challenges[number].size = _challenge.size - size;\n        } else {\n            require(size == _challenge.size);\n            delete challenges[number];\n        }\n        if (asNative && address(_challenge.position.collateral()) == WETH) {\n            IWrappedNative(WETH).withdraw(size);\n            (bool success, ) = msg.sender.call{value: size}(\"\");\n            if (!success) revert NativeTransferFailed();\n        } else {\n            _challenge.position.collateral().transfer(msg.sender, size);\n        }\n    }\n\n    /**\n     * @notice Returns 'amount' of the collateral to the challenger and reduces or deletes the relevant challenge.\n     */\n    function _returnChallengerCollateral(\n        Challenge memory _challenge,\n        uint256 number,\n        uint256 amount,\n        bool postpone,\n        bool asNative\n    ) internal {\n        if (_challenge.size == amount) {\n            // bid on full amount\n            delete challenges[number];\n        } else {\n            // bid on partial amount\n            challenges[number].size -= amount;\n        }\n        _returnCollateral(_challenge.position.collateral(), _challenge.challenger, amount, postpone, asNative);\n    }\n\n    /**\n     * @notice Calculates the current Dutch auction price.\n     * @dev Starts at the full price at time 'start' and linearly goes to 0 as 'phase2' passes.\n     */\n    function _calculatePrice(uint40 start, uint40 phase2, uint256 liqPrice) internal view returns (uint256) {\n        uint40 timeNow = uint40(block.timestamp);\n        if (timeNow <= start) {\n            return liqPrice;\n        } else if (timeNow >= start + phase2) {\n            return 0;\n        } else {\n            uint256 timeLeft = phase2 - (timeNow - start);\n            return (liqPrice * timeLeft) / phase2;\n        }\n    }\n\n    /**\n     * @notice Returns the current unit price for the given challenge's collateral.\n     * @dev Must be called before notifyChallengeSucceeded(), which mutates challengedAmount and debt.\n     */\n    function _challengeUnitPrice(Challenge memory _challenge) internal view returns (uint256) {\n        (uint256 liqPrice, uint40 phase) = _challenge.position.challengeData();\n        return _calculatePrice(_challenge.start + phase, phase, liqPrice);\n    }\n\n    /**\n     * @notice Get the price per unit of the collateral for the given challenge.\n     * @dev The price comes with (36 - collateral.decimals()) digits, so multiplying it with the raw collateral amount\n     * always yields a price with 36 digits, or 18 digits after dividing by 10**18 again.\n     */\n    function price(uint256 challengeNumber) public view returns (uint256) {\n        Challenge memory _challenge = challenges[challengeNumber];\n        if (_challenge.challenger == address(0x0)) {\n            return 0;\n        } else {\n            (uint256 liqPrice, uint40 phase) = _challenge.position.challengeData();\n            return _calculatePrice(_challenge.start + phase, phase, liqPrice);\n        }\n    }\n\n    /**\n     * @notice Challengers can call this method to withdraw collateral whose return was postponed.\n     */\n    function returnPostponedCollateral(address collateral, address target, bool asNative) external {\n        _returnPostponedCollateral(collateral, target, asNative);\n    }\n\n    /**\n     * @notice Challengers can call this method to withdraw collateral whose return was postponed (backward compatible).\n     */\n    function returnPostponedCollateral(address collateral, address target) external {\n        _returnPostponedCollateral(collateral, target, false);\n    }\n\n    function _returnPostponedCollateral(address collateral, address target, bool asNative) internal {\n        uint256 amount = pendingReturns[collateral][msg.sender];\n        delete pendingReturns[collateral][msg.sender];\n        if (asNative && collateral == WETH) {\n            IWrappedNative(WETH).withdraw(amount);\n            (bool success, ) = target.call{value: amount}(\"\");\n            if (!success) revert NativeTransferFailed();\n        } else {\n            IERC20(collateral).transfer(target, amount);\n        }\n    }\n\n    function _returnCollateral(IERC20 collateral, address recipient, uint256 amount, bool postpone, bool asNative) internal {\n        if (postpone) {\n            // Postponing helps in case the challenger was blacklisted or otherwise cannot receive at the moment.\n            pendingReturns[address(collateral)][recipient] += amount;\n            emit PostponedReturn(address(collateral), recipient, amount);\n        } else if (asNative && address(collateral) == WETH) {\n            IWrappedNative(WETH).withdraw(amount);\n            (bool success, ) = recipient.call{value: amount}(\"\");\n            if (!success) revert NativeTransferFailed();\n        } else {\n            collateral.transfer(recipient, amount); // return the challenger's collateral\n        }\n    }\n\n    /**\n     * The applicable purchase price when forcing the sale of collateral of an expired position.\n     *\n     * The price starts at 10x the liquidation price at the expiration time, linearly declines to\n     * 1x liquidation price over the course of one challenge period, and then linearly declines\n     * less steeply to 0 over the course of another challenge period.\n     */\n    function expiredPurchasePrice(IPosition pos) public view returns (uint256) {\n        uint256 liqprice = pos.virtualPrice();\n        uint256 expiration = pos.expiration();\n        if (block.timestamp <= expiration) {\n            return EXPIRED_PRICE_FACTOR * liqprice;\n        } else {\n            uint256 challengePeriod = pos.challengePeriod();\n            uint256 timePassed = block.timestamp - expiration;\n            if (timePassed <= challengePeriod) {\n                // from 10x liquidation price to 1x in first phase\n                uint256 timeLeft = challengePeriod - timePassed;\n                return liqprice + (((EXPIRED_PRICE_FACTOR - 1) * liqprice * timeLeft) / challengePeriod);\n            } else if (timePassed < 2 * challengePeriod) {\n                // from 1x liquidation price to 0 in second phase\n                uint256 timeLeft = 2 * challengePeriod - timePassed;\n                return (liqprice * timeLeft) / challengePeriod;\n            } else {\n                // get collateral for free after both phases passed\n                return 0;\n            }\n        }\n    }\n\n    /**\n     * Buys up to the desired amount of the collateral asset from the given expired position using\n     * the applicable 'expiredPurchasePrice' at that instant.\n     *\n     * To prevent dust either the remaining collateral needs to be bought or collateral with a value\n     * of at least OPENING_FEE (1000 dEURO) needs to remain in the position for a different buyer\n     */\n    function buyExpiredCollateral(IPosition pos, uint256 upToAmount, bool receiveAsNative) external validPos(address(pos)) returns (uint256) {\n        return _buyExpiredCollateral(pos, upToAmount, receiveAsNative);\n    }\n\n    /**\n     * @notice Buy expired collateral (backward compatible).\n     */\n    function buyExpiredCollateral(IPosition pos, uint256 upToAmount) external validPos(address(pos)) returns (uint256) {\n        return _buyExpiredCollateral(pos, upToAmount, false);\n    }\n\n    function _buyExpiredCollateral(IPosition pos, uint256 upToAmount, bool receiveAsNative) internal returns (uint256) {\n        address collateralAddr = address(pos.collateral());\n        uint256 max = IERC20(collateralAddr).balanceOf(address(pos));\n        uint256 amount = upToAmount > max ? max : upToAmount;\n        uint256 forceSalePrice = expiredPurchasePrice(pos);\n\n        uint256 costs = (forceSalePrice * amount) / 10 ** 18;\n\n        if (max - amount > 0 && ((forceSalePrice * (max - amount)) / 10 ** 18) < OPENING_FEE) {\n            revert LeaveNoDust(max - amount);\n        }\n\n        if (receiveAsNative && collateralAddr == WETH) {\n            DEURO.transferFrom(msg.sender, address(this), costs);\n            DEURO.approve(address(pos), costs);\n            pos.forceSale(address(this), amount, costs);\n            IWrappedNative(WETH).withdraw(amount);\n            (bool success, ) = msg.sender.call{value: amount}(\"\");\n            if (!success) revert NativeTransferFailed();\n        } else {\n            pos.forceSale(msg.sender, amount, costs);\n        }\n\n        emit ForcedSale(address(pos), amount, forceSalePrice);\n        return amount;\n    }\n\n    /**\n     * @dev See {IERC165-supportsInterface}.\n     */\n    function supportsInterface(bytes4 interfaceId) public view override virtual returns (bool) {\n        return\n            interfaceId == type(IMintingHub).interfaceId ||\n            super.supportsInterface(interfaceId);\n    }\n\n    /**\n     * @dev Required for WETH.withdraw() callbacks.\n     */\n    receive() external payable {}\n\n}\n","deployed_bytecode":"0x6080604052600436106101dc5760003560e01c80638f1d377611610102578063cb2b87b211610095578063e6ac5ea411610064578063e6ac5ea4146105f5578063e85cde6f14610615578063f09e9e3a14610635578063f32ddc2d1461066957600080fd5b8063cb2b87b21461056e578063d6d87bdb1461058e578063dbe8a4c2146105ae578063e29bf421146105e257600080fd5b8063af5806b6116100d1578063af5806b6146104f5578063b079f1631461050b578063b6f83c1714610520578063c14a9f051461055b57600080fd5b80638f1d3776146104155780639064ae7c1461046d57806391a0ac6a1461048d578063ad5c4648146104c157600080fd5b80632bf78dd81161017a578063534cb30d11610149578063534cb30d14610372578063643745fb146103aa578063664e9704146103e257806386a7c248146103f557600080fd5b80632bf78dd8146102f25780632e4b20ab1461030f57806335a4b349146103325780634e65037e1461035d57600080fd5b8063187dcc05116101b6578063187dcc05146102705780631de252e41461029257806325e28124146102b257806326a49e37146102d257600080fd5b806301ffc9a7146101e857806306a7b3761461021d5780630f2f8e861461024d57600080fd5b366101e357005b600080fd5b3480156101f457600080fd5b50610208610203366004613c41565b610689565b60405190151581526020015b60405180910390f35b34801561022957600080fd5b506000546102399062ffffff1681565b60405162ffffff9091168152602001610214565b34801561025957600080fd5b50610262600a81565b604051908152602001610214565b34801561027c57600080fd5b5061029061028b366004613c91565b6106c0565b005b34801561029e57600080fd5b506102906102ad366004613cf4565b6106d0565b3480156102be57600080fd5b506102626102cd366004613d7a565b6107f8565b3480156102de57600080fd5b506102626102ed366004613da6565b6108c8565b3480156102fe57600080fd5b50610262683635c9adc5dea0000081565b34801561031b57600080fd5b50600054610239906301000000900462ffffff1681565b610345610340366004613dd2565b6109d8565b6040516001600160a01b039091168152602001610214565b34801561036957600080fd5b5061029061110d565b34801561037e57600080fd5b5061039261038d366004613da6565b611276565b6040516001600160401b039091168152602001610214565b3480156103b657600080fd5b506102626103c5366004613e78565b600260209081526000928352604080842090915290825290205481565b3480156103ee57600080fd5b5030610345565b34801561040157600080fd5b50610262610410366004613eb1565b6112c0565b34801561042157600080fd5b50610435610430366004613da6565b611385565b604080516001600160a01b03958616815264ffffffffff94909416602085015291909316908201526060810191909152608001610214565b34801561047957600080fd5b50610290610488366004613ee8565b6113d7565b34801561049957600080fd5b506103457f000000000000000000000000c71104001a3ccda1bef1177d765831bd1bfe8ee681565b3480156104cd57600080fd5b506103457f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b34801561050157600080fd5b50610262614e2081565b34801561051757600080fd5b506103926113e4565b34801561052c57600080fd5b5060005461054590600160301b900464ffffffffff1681565b60405164ffffffffff9091168152602001610214565b610262610569366004613f16565b6113f4565b34801561057a57600080fd5b50610290610589366004613f4b565b6118bf565b34801561059a57600080fd5b506102906105a9366004613f95565b6118d1565b3480156105ba57600080fd5b506103457f000000000000000000000000ba3f535bbcccca2a154b573ca6c5a49baae0a3ea81565b6103456105f0366004613fc1565b6119ce565b34801561060157600080fd5b50610262610610366004614028565b6120a8565b34801561062157600080fd5b50610290610630366004613e78565b6122b5565b34801561064157600080fd5b506103457f0000000000000000000000005c22d5b752b2121fae7f6f0069252b03b2f7c5cd81565b34801561067557600080fd5b50610290610684366004614045565b6122c5565b60006001600160e01b03198216630d60fedb60e21b14806106ba57506301ffc9a760e01b6001600160e01b03198316145b92915050565b6106cb8383836123cc565b505050565b60405163352e3a8360e01b81526001600160a01b037f000000000000000000000000c71104001a3ccda1bef1177d765831bd1bfe8ee6169063352e3a8390610720903390869086906004016140b9565b60006040518083038186803b15801561073857600080fd5b505afa15801561074c573d6000803e3d6000fd5b50506000805465ffffff0000001916630100000062ffffff8816021790555061077a90504262093a8061412d565b600080546affffffffff0000000000001916600160301b64ffffffffff93841681029190911791829055604080513381526301000000840462ffffff16602082015291909204909216908201527e4964f2e48bd8a460fb41883098593956d335f36fdded4ca9cbac9252d72b2f9060600160405180910390a1505050565b60405163aa5dd7f160e01b81526001600160a01b038381166004830152600091849130917f000000000000000000000000ba3f535bbcccca2a154b573ca6c5a49baae0a3ea9091169063aa5dd7f190602401602060405180830381865afa158015610867573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061088b9190614140565b6001600160a01b0316146108b2576040516369229ba760e01b815260040160405180910390fd5b6108be848460006125a3565b91505b5092915050565b600080600183815481106108de576108de61415d565b60009182526020918290206040805160808101825260039390930290910180546001600160a01b03808216808652600160a01b90920464ffffffffff169585019590955260018201549094169183019190915260020154606082015291506109495750600092915050565b60008082604001516001600160a01b031663329864aa6040518163ffffffff1660e01b81526004016040805180830381865afa15801561098d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109b19190614173565b915091506109cf8184602001516109c89190614199565b8284612ab0565b95945050505050565b6000620f42408462ffffff161115610a035760405163b2772c5d60e01b815260040160405180910390fd5b8162ffffff16614e201180610a1f5750620f42408262ffffff16115b15610a3d57604051633a3626e360e21b815260040160405180910390fd5b60188b6001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a7d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aa191906141b6565b60ff161115610ac3576040516325dd4a5560e21b815260040160405180910390fd5b620151808564ffffffffff161015610aee5760405163fc8c61b960e01b815260040160405180910390fd5b6203f4808764ffffffffff161015610b195760405163f979252f60e01b815260040160405180910390fd5b60008b6001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b59573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b7d91906141d9565b610b8890600161412d565b60405163a9059cbb60e01b81529091506001600160a01b038d169063a9059cbb90610bbb906101239085906004016141f2565b6020604051808303816000875af1925050508015610bf6575060408051601f3d908101601f19168201909252610bf39181019061420b565b60015b610c7657610c02614228565b806308c379a003610c275750610c1661427e565b80610c215750610c40565b50610c90565b634e487b7103610c4057610c39614301565b90610c2157505b3d808015610c6a576040519150601f19603f3d011682016040523d82523d6000602084013e610c6f565b606091505b5050610c90565b506040516343befb6960e11b815260040160405180910390fd5b8a8a1015610cb157604051633a23d82560e01b815260040160405180910390fd5b700178287f49c4a1d6622fb2ab4000000000610ccd858d614321565b1015610cec57604051633a23d82560e01b815260040160405180910390fd5b5060007f0000000000000000000000003a3985a96b1b51e6d914bc7c9e89fd6ba6defe816001600160a01b0316635d824f76337f000000000000000000000000ba3f535bbcccca2a154b573ca6c5a49baae0a3ea8f8f8e8e8e8e8e8e8e6040518c63ffffffff1660e01b8152600401610d6f9b9a99989796959493929190614338565b6020604051808303816000875af1158015610d8e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610db29190614140565b60405163b52c696d60e01b81526001600160a01b0380831660048301529192507f000000000000000000000000ba3f535bbcccca2a154b573ca6c5a49baae0a3ea9091169063b52c696d90602401600060405180830381600087803b158015610e1a57600080fd5b505af1158015610e2e573d6000803e3d6000fd5b505060405163375edc7760e11b81526001600160a01b037f000000000000000000000000ba3f535bbcccca2a154b573ca6c5a49baae0a3ea169250636ebdb8ee9150610e89903390683635c9adc5dea00000906004016141f2565b600060405180830381600087803b158015610ea357600080fd5b505af1158015610eb7573d6000803e3d6000fd5b505050506000341115611041577f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b03168c6001600160a01b031614610f1657604051631a38687560e21b815260040160405180910390fd5b893414610f365760405163dd8e4af760e01b815260040160405180910390fd5b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015610f9157600080fd5b505af1158015610fa5573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216935063a9059cbb9250610ff8915084908e906004016141f2565b6020604051808303816000875af1158015611017573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061103b919061420b565b506110b6565b6040516323b872dd60e01b81526001600160a01b038d16906323b872dd9061107190339085908f906004016143b9565b6020604051808303816000875af1158015611090573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110b4919061420b565b505b604080516001600160a01b03808416808352908f1660208301529133917fc9b570ab9d98bdf3e38a40fd71b20edafca42449f23ca51f0bdcbf40e8ffe175910160405180910390a39b9a5050505050505050505050565b60005462ffffff63010000008204811691160361113d5760405163147fde5f60e31b815260040160405180910390fd5b600054429064ffffffffff600160301b90910481169082161015611174576040516301b3782160e21b815260040160405180910390fd5b60005462ffffff81169061119690600160581b900464ffffffffff16836143dd565b64ffffffffff166111a791906143fa565b600080546010906111c9908490600160801b90046001600160401b031661441c565b82546101009290920a6001600160401b038181021990931691909216919091021790555060008054630100000064ffffffffff60581b198216600160581b64ffffffffff8616029081179190910462ffffff166fffffffffff0000000000000000ffffff1990921662ffffff19919091161781179091556040519081527fd76dfbd4c35cffe2a846b6488bc677c511aa4337e1551f3a360427ac7a78de7b9060200160405180910390a150565b6000805462ffffff81169061129990600160581b900464ffffffffff168461443b565b6112a391906143fa565b6000546106ba9190600160801b90046001600160401b031661441c565b60405163aa5dd7f160e01b81526001600160a01b038481166004830152600091859130917f000000000000000000000000ba3f535bbcccca2a154b573ca6c5a49baae0a3ea9091169063aa5dd7f190602401602060405180830381865afa15801561132f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113539190614140565b6001600160a01b03161461137a576040516369229ba760e01b815260040160405180910390fd5b6109cf8585856125a3565b6001818154811061139557600080fd5b60009182526020909120600390910201805460018201546002909201546001600160a01b038083169450600160a01b90920464ffffffffff1692919091169084565b6106cb8383836000612b35565b60006113ef42611276565b905090565b60405163aa5dd7f160e01b81526001600160a01b038481166004830152600091859130917f000000000000000000000000ba3f535bbcccca2a154b573ca6c5a49baae0a3ea9091169063aa5dd7f190602401602060405180830381865afa158015611463573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114879190614140565b6001600160a01b0316146114ae576040516369229ba760e01b815260040160405180910390fd5b60008590506000816001600160a01b0316638ea875f36040518163ffffffff1660e01b8152600401602060405180830381865afa1580156114f3573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061151791906141d9565b90508481101561153a57604051630d57523160e11b815260040160405180910390fd5b6000826001600160a01b031663d8dfeb456040518163ffffffff1660e01b8152600401602060405180830381865afa15801561157a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061159e9190614140565b90503415611691577f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316816001600160a01b0316146115f857604051631a38687560e21b815260040160405180910390fd5b8634146116185760405163dd8e4af760e01b815260040160405180910390fd5b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561167357600080fd5b505af1158015611687573d6000803e3d6000fd5b5050505050611706565b6040516323b872dd60e01b81526001600160a01b038216906323b872dd906116c190339030908c906004016143b9565b6020604051808303816000875af11580156116e0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611704919061420b565b505b6000600180549050905060016040518060800160405280336001600160a01b031681526020014264ffffffffff168152602001866001600160a01b031681526020018a815250908060018154018082558091505060019003906000526020600020906003020160009091909190915060008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060208201518160000160146101000a81548164ffffffffff021916908364ffffffffff16021790555060408201518160010160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550606082015181600201555050836001600160a01b031663b8e2426c89856040518363ffffffff1660e01b815260040161183b929190918252602082015260400190565b600060405180830381600087803b15801561185557600080fd5b505af1158015611869573d6000803e3d6000fd5b5050604080518b8152602081018590526001600160a01b03881693503392507fc4b384b2c5ca32c8e77081f4083be594a1ea9ba34f208a9f9a458f70608585f5910160405180910390a398975050505050505050565b6118cb84848484612b35565b50505050565b60405163aa5dd7f160e01b815233600482018190529030906001600160a01b037f000000000000000000000000ba3f535bbcccca2a154b573ca6c5a49baae0a3ea169063aa5dd7f190602401602060405180830381865afa15801561193a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061195e9190614140565b6001600160a01b031614611985576040516369229ba760e01b815260040160405180910390fd5b604080518581526020810185905290810183905233907f0f16da76fa675fc06a1439cf962e8f7ae36ec73aa5264a2f06fb4214b23898e29060600160405180910390a250505050565b60405163aa5dd7f160e01b81526001600160a01b038681166004830152600091879130917f000000000000000000000000ba3f535bbcccca2a154b573ca6c5a49baae0a3ea9091169063aa5dd7f190602401602060405180830381865afa158015611a3d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a619190614140565b6001600160a01b031614611a88576040516369229ba760e01b815260040160405180910390fd5b604051630167d12360e71b81526001600160a01b0388811660048301526000917f0000000000000000000000003a3985a96b1b51e6d914bc7c9e89fd6ba6defe819091169063b3e89180906024016020604051808303816000875af1158015611af5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b199190614140565b6040516336a3a4fd60e11b81526001600160a01b038a8116600483015264ffffffffff881660248301529192508291821690636d4749fa90604401600060405180830381600087803b158015611b6e57600080fd5b505af1158015611b82573d6000803e3d6000fd5b505060405163b52c696d60e01b81526001600160a01b0385811660048301527f000000000000000000000000ba3f535bbcccca2a154b573ca6c5a49baae0a3ea16925063b52c696d9150602401600060405180830381600087803b158015611be957600080fd5b505af1158015611bfd573d6000803e3d6000fd5b505050506000816001600160a01b031663d8dfeb456040518163ffffffff1660e01b8152600401602060405180830381865afa158015611c41573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c659190614140565b9050816001600160a01b031663babe7c746040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ca5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cc991906141d9565b891015611ce957604051633a23d82560e01b815260040160405180910390fd5b3415611e4c577f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316816001600160a01b031614611d4157604051631a38687560e21b815260040160405180910390fd5b883414611d615760405163dd8e4af760e01b815260040160405180910390fd5b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015611dbc57600080fd5b505af1158015611dd0573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b038516935063a9059cbb9250611e03915086908d906004016141f2565b6020604051808303816000875af1158015611e22573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e46919061420b565b50611ec1565b6040516323b872dd60e01b81526001600160a01b038216906323b872dd90611e7c90339087908e906004016143b9565b6020604051808303816000875af1158015611e9b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ebf919061420b565b505b604080516001600160a01b038c81168252838116602083015280861692908e16917fc9b570ab9d98bdf3e38a40fd71b20edafca42449f23ca51f0bdcbf40e8ffe175910160405180910390a36040516340c10f1960e01b81526001600160a01b038316906340c10f1990611f3b908e908c906004016141f2565b600060405180830381600087803b158015611f5557600080fd5b505af1158015611f69573d6000803e3d6000fd5b50505050600086118015611fde5750816001600160a01b031663a035b1fe6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611fb6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fda91906141d9565b8614155b1561203e5760405163395f83cf60e11b8152600481018790526001600160a01b038316906372bf079e90602401600060405180830381600087803b15801561202557600080fd5b505af1158015612039573d6000803e3d6000fd5b505050505b60405163f2fde38b60e01b81526001600160a01b038c8116600483015283169063f2fde38b90602401600060405180830381600087803b15801561208157600080fd5b505af1158015612095573d6000803e3d6000fd5b50949d9c50505050505050505050505050565b600080826001600160a01b0316638ea875f36040518163ffffffff1660e01b8152600401602060405180830381865afa1580156120e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061210d91906141d9565b90506000836001600160a01b0316634665096d6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561214f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612173919061445a565b64ffffffffff1690508042116121965761218e82600a614321565b949350505050565b6000846001600160a01b031663f3f480d96040518163ffffffff1660e01b8152600401602060405180830381865afa1580156121d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121fa919061445a565b64ffffffffff169050600061220f8342614477565b90508181116122685760006122248284614477565b90508281866122356001600a614477565b61223f9190614321565b6122499190614321565b612253919061448a565b61225d908661412d565b979650505050505050565b612273826002614321565b8110156122a957600081612288846002614321565b6122929190614477565b90508261229f8287614321565b61225d919061448a565b50600095945050505050565b6122c1828260006123cc565b5050565b60405163aa5dd7f160e01b815233600482018190529030906001600160a01b037f000000000000000000000000ba3f535bbcccca2a154b573ca6c5a49baae0a3ea169063aa5dd7f190602401602060405180830381865afa15801561232e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123529190614140565b6001600160a01b031614612379576040516369229ba760e01b815260040160405180910390fd5b836001600160a01b0316336001600160a01b03167f7e020a844d0d659902f4ca7ee9c4873e8c34253de5b150c7d64258e30965191185856040516123be9291906144ac565b60405180910390a350505050565b6001600160a01b03831660009081526002602090815260408083203384529091528120805491905581801561243257507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316846001600160a01b0316145b1561252b57604051632e1a7d4d60e01b8152600481018290527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561249957600080fd5b505af11580156124ad573d6000803e3d6000fd5b505050506000836001600160a01b03168260405160006040518083038185875af1925050503d80600081146124fe576040519150601f19603f3d011682016040523d82523d6000602084013e612503565b606091505b505090508061252557604051633d2cec6f60e21b815260040160405180910390fd5b506118cb565b60405163a9059cbb60e01b81526001600160a01b0385169063a9059cbb9061255990869085906004016141f2565b6020604051808303816000875af1158015612578573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061259c919061420b565b5050505050565b600080846001600160a01b031663d8dfeb456040518163ffffffff1660e01b8152600401602060405180830381865afa1580156125e4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126089190614140565b6040516370a0823160e01b81526001600160a01b0387811660048301529192506000918316906370a0823190602401602060405180830381865afa158015612654573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061267891906141d9565b90506000818611612689578561268b565b815b90506000612698886120a8565b90506000670de0b6b3a76400006126af8484614321565b6126b9919061448a565b905060006126c78486614477565b1180156127025750683635c9adc5dea00000670de0b6b3a76400006126ec8587614477565b6126f69085614321565b612700919061448a565b105b15612736576127118385614477565b60405163f658c6cf60e01b815260040161272d91815260200190565b60405180910390fd5b86801561277457507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316856001600160a01b0316145b156129ef576040516323b872dd60e01b81526001600160a01b037f000000000000000000000000ba3f535bbcccca2a154b573ca6c5a49baae0a3ea16906323b872dd906127c9903390309086906004016143b9565b6020604051808303816000875af11580156127e8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061280c919061420b565b5060405163095ea7b360e01b81526001600160a01b037f000000000000000000000000ba3f535bbcccca2a154b573ca6c5a49baae0a3ea169063095ea7b39061285b908c9085906004016141f2565b6020604051808303816000875af115801561287a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061289e919061420b565b5060405163211d798360e01b815230600482015260248101849052604481018290526001600160a01b038a169063211d798390606401600060405180830381600087803b1580156128ee57600080fd5b505af1158015612902573d6000803e3d6000fd5b5050604051632e1a7d4d60e01b8152600481018690527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b03169250632e1a7d4d9150602401600060405180830381600087803b15801561296857600080fd5b505af115801561297c573d6000803e3d6000fd5b50506040516000925033915085908381818185875af1925050503d80600081146129c2576040519150601f19603f3d011682016040523d82523d6000602084013e6129c7565b606091505b50509050806129e957604051633d2cec6f60e21b815260040160405180910390fd5b50612a57565b60405163211d798360e01b815233600482015260248101849052604481018290526001600160a01b038a169063211d798390606401600060405180830381600087803b158015612a3e57600080fd5b505af1158015612a52573d6000803e3d6000fd5b505050505b604080516001600160a01b038b168152602081018590529081018390527f67a660133c1fb4c0bb0480a5e4a9919216684052f13f0713e88fa2fbbc81d0829060600160405180910390a1509093505050505b9392505050565b60004264ffffffffff80861690821611612acd5782915050612aa9565b612ad78486614199565b64ffffffffff168164ffffffffff1610612af5576000915050612aa9565b6000612b0186836143dd565b612b0b90866143dd565b64ffffffffff90811691508516612b228286614321565b612b2c919061448a565b92505050612aa9565b600060018581548110612b4a57612b4a61415d565b600091825260208083206040805160808101825260039490940290910180546001600160a01b038082168652600160a01b90910464ffffffffff169385019390935260018101549092168382018190526002909201546060840152805163194c325560e11b81528151939550849363329864aa926004808401939192918290030181865afa158015612be0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c049190614173565b9150915085836060015110612c195785612c1f565b82606001515b9550808360200151612c319190614199565b64ffffffffff164211612ca057612c4b8388848988612d2c565b82604001516001600160a01b03167f1eee30d91b773ac47d7485a3acb6bcd8c7c9cd8d95301b1af361baf5f0991d2e8888604051612c93929190918252602082015260400190565b60405180910390a2612d23565b612cad8388888888613188565b600080612cbb85898861328b565b9150915084604001516001600160a01b03167f7d3a26e8d43c5b70f86266bfa26c212e3c097716ff7240ccb6a9034e48754e238a83858c604051612d18949392919093845260208401929092526040830152606082015260800190565b60405180910390a250505b50505050505050565b846020015164ffffffffff164203612d4357600080fd5b84516001600160a01b03163314612e095784516001600160a01b037f000000000000000000000000ba3f535bbcccca2a154b573ca6c5a49baae0a3ea16906323b872dd903390670de0b6b3a7640000612d9c8888614321565b612da6919061448a565b6040518463ffffffff1660e01b8152600401612dc4939291906143b9565b6020604051808303816000875af1158015612de3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e07919061420b565b505b84604001516001600160a01b03166349746f10836040518263ffffffff1660e01b8152600401612e3b91815260200190565b600060405180830381600087803b158015612e5557600080fd5b505af1158015612e69573d6000803e3d6000fd5b505050508460600151821015612eb657818560600151612e899190614477565b60018581548110612e9c57612e9c61415d565b906000526020600020906003020160020181905550612f0d565b84606001518214612ec657600080fd5b60018481548110612ed957612ed961415d565b60009182526020822060039091020180546001600160c81b03191681556001810180546001600160a01b0319169055600201555b808015612fb057507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031685604001516001600160a01b031663d8dfeb456040518163ffffffff1660e01b8152600401602060405180830381865afa158015612f81573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fa59190614140565b6001600160a01b0316145b156130aa57604051632e1a7d4d60e01b8152600481018390527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561301757600080fd5b505af115801561302b573d6000803e3d6000fd5b505050506000336001600160a01b0316836040515b60006040518083038185875af1925050503d806000811461307d576040519150601f19603f3d011682016040523d82523d6000602084013e613082565b606091505b50509050806130a457604051633d2cec6f60e21b815260040160405180910390fd5b5061259c565b84604001516001600160a01b031663d8dfeb456040518163ffffffff1660e01b8152600401602060405180830381865afa1580156130ec573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131109190614140565b6001600160a01b031663a9059cbb33846040518363ffffffff1660e01b815260040161313d9291906141f2565b6020604051808303816000875af115801561315c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613180919061420b565b505050505050565b828560600151036131de57600184815481106131a6576131a661415d565b60009182526020822060039091020180546001600160c81b03191681556001810180546001600160a01b031916905560020155613218565b82600185815481106131f2576131f261415d565b906000526020600020906003020160020160008282546132129190614477565b90915550505b61259c85604001516001600160a01b031663d8dfeb456040518163ffffffff1660e01b8152600401602060405180830381865afa15801561325d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132819190614140565b8651858585613a34565b600080600061329986613bc0565b905060008060008060008a604001516001600160a01b0316637ccd4f718b6040518263ffffffff1660e01b81526004016132d591815260200190565b60a0604051808303816000875af11580156132f4573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061331891906144db565b945094509450945094506000670de0b6b3a764000085886133399190614321565b613343919061448a565b6040516323b872dd60e01b81529091506001600160a01b037f000000000000000000000000ba3f535bbcccca2a154b573ca6c5a49baae0a3ea16906323b872dd90613396903390309086906004016143b9565b6020604051808303816000875af11580156133b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133d9919061420b565b506000620f42406133ec614e2084614321565b6133f6919061448a565b8d5160405163a9059cbb60e01b81529192506001600160a01b037f000000000000000000000000ba3f535bbcccca2a154b573ca6c5a49baae0a3ea169163a9059cbb916134479185906004016141f2565b6020604051808303816000875af1158015613466573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061348a919061420b565b5060006134978284614477565b90506134a3858761412d565b81111561361b576000620f4240866134bb8985614477565b6134c59190614477565b6134d59063ffffffff8816614321565b6134df919061448a565b60405163375edc7760e11b81529091506001600160a01b037f000000000000000000000000ba3f535bbcccca2a154b573ca6c5a49baae0a3ea1690636ebdb8ee9061353090309085906004016141f2565b600060405180830381600087803b15801561354a57600080fd5b505af115801561355e573d6000803e3d6000fd5b505050507f000000000000000000000000ba3f535bbcccca2a154b573ca6c5a49baae0a3ea6001600160a01b031663a9059cbb8a83898b876135a09190614477565b6135aa9190614477565b6135b49190614477565b6040518363ffffffff1660e01b81526004016135d19291906141f2565b6020604051808303816000875af11580156135f0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613614919061420b565b50506136c1565b613625858761412d565b8110156136c1576001600160a01b037f000000000000000000000000ba3f535bbcccca2a154b573ca6c5a49baae0a3ea1663d1fa5e983083613667898b61412d565b6136719190614477565b6040518363ffffffff1660e01b815260040161368e9291906141f2565b600060405180830381600087803b1580156136a857600080fd5b505af11580156136bc573d6000803e3d6000fd5b505050505b6040516363b20c3360e11b81526004810187905263ffffffff851660248201527f000000000000000000000000ba3f535bbcccca2a154b573ca6c5a49baae0a3ea6001600160a01b03169063c764186690604401600060405180830381600087803b15801561372f57600080fd5b505af1158015613743573d6000803e3d6000fd5b505060405163375edc7760e11b81526001600160a01b037f000000000000000000000000ba3f535bbcccca2a154b573ca6c5a49baae0a3ea169250636ebdb8ee915061379590309089906004016141f2565b600060405180830381600087803b1580156137af57600080fd5b505af11580156137c3573d6000803e3d6000fd5b505050508b801561386a57507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b03168e604001516001600160a01b031663d8dfeb456040518163ffffffff1660e01b8152600401602060405180830381865afa15801561383b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061385f9190614140565b6001600160a01b0316145b156139bc578d604001516001600160a01b0316631dbcff2630896040518363ffffffff1660e01b81526004016138a19291906141f2565b600060405180830381600087803b1580156138bb57600080fd5b505af11580156138cf573d6000803e3d6000fd5b5050604051632e1a7d4d60e01b8152600481018a90527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b03169250632e1a7d4d9150602401600060405180830381600087803b15801561393557600080fd5b505af1158015613949573d6000803e3d6000fd5b50506040516000925033915089908381818185875af1925050503d806000811461398f576040519150601f19603f3d011682016040523d82523d6000602084013e613994565b606091505b50509050806139b657604051633d2cec6f60e21b815260040160405180910390fd5b50613a21565b8d604001516001600160a01b0316631dbcff2633896040518363ffffffff1660e01b81526004016139ee9291906141f2565b600060405180830381600087803b158015613a0857600080fd5b505af1158015613a1c573d6000803e3d6000fd5b505050505b50949c909b509950505050505050505050565b8115613ac0576001600160a01b03808616600090815260026020908152604080832093881683529290529081208054859290613a7190849061412d565b92505081905550836001600160a01b03167f8dbeeabb7d576986689d0bff912a01b9736f03d95739a5603e59301a50141c5c8685604051613ab39291906141f2565b60405180910390a261259c565b808015613afe57507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316856001600160a01b0316145b15613b9257604051632e1a7d4d60e01b8152600481018490527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031690632e1a7d4d90602401600060405180830381600087803b158015613b6557600080fd5b505af1158015613b79573d6000803e3d6000fd5b505050506000846001600160a01b031684604051613040565b60405163a9059cbb60e01b81526001600160a01b0386169063a9059cbb9061313d90879087906004016141f2565b600080600083604001516001600160a01b031663329864aa6040518163ffffffff1660e01b81526004016040805180830381865afa158015613c06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c2a9190614173565b9150915061218e8185602001516109c89190614199565b600060208284031215613c5357600080fd5b81356001600160e01b031981168114612aa957600080fd5b6001600160a01b0381168114613c8057600080fd5b50565b8015158114613c8057600080fd5b600080600060608486031215613ca657600080fd5b8335613cb181613c6b565b92506020840135613cc181613c6b565b91506040840135613cd181613c83565b809150509250925092565b803562ffffff81168114613cef57600080fd5b919050565b600080600060408486031215613d0957600080fd5b613d1284613cdc565b925060208401356001600160401b03811115613d2d57600080fd5b8401601f81018613613d3e57600080fd5b80356001600160401b03811115613d5457600080fd5b8660208260051b8401011115613d6957600080fd5b939660209190910195509293505050565b60008060408385031215613d8d57600080fd5b8235613d9881613c6b565b946020939093013593505050565b600060208284031215613db857600080fd5b5035919050565b64ffffffffff81168114613c8057600080fd5b6000806000806000806000806000806101408b8d031215613df257600080fd5b8a35613dfd81613c6b565b995060208b0135985060408b0135975060608b0135965060808b0135613e2281613dbf565b955060a08b0135613e3281613dbf565b945060c08b0135613e4281613dbf565b9350613e5060e08c01613cdc565b92506101008b01359150613e676101208c01613cdc565b90509295989b9194979a5092959850565b60008060408385031215613e8b57600080fd5b8235613e9681613c6b565b91506020830135613ea681613c6b565b809150509250929050565b600080600060608486031215613ec657600080fd5b8335613ed181613c6b565b9250602084013591506040840135613cd181613c83565b600080600060608486031215613efd57600080fd5b83359250602084013591506040840135613cd181613c83565b600080600060608486031215613f2b57600080fd5b8335613f3681613c6b565b95602085013595506040909401359392505050565b60008060008060808587031215613f6157600080fd5b84359350602085013592506040850135613f7a81613c83565b91506060850135613f8a81613c83565b939692955090935050565b600080600060608486031215613faa57600080fd5b505081359360208301359350604090920135919050565b60008060008060008060c08789031215613fda57600080fd5b8635613fe581613c6b565b95506020870135613ff581613c6b565b94506040870135935060608701359250608087013561401381613dbf565b9598949750929591949360a090920135925050565b60006020828403121561403a57600080fd5b8135612aa981613c6b565b60008060006040848603121561405a57600080fd5b833561406581613c6b565b925060208401356001600160401b0381111561408057600080fd5b8401601f8101861361409157600080fd5b80356001600160401b038111156140a757600080fd5b866020828401011115613d6957600080fd5b6001600160a01b0384168152604060208201819052810182905260008360608301825b8581101561410c5782356140ef81613c6b565b6001600160a01b03168252602092830192909101906001016140dc565b509695505050505050565b634e487b7160e01b600052601160045260246000fd5b808201808211156106ba576106ba614117565b60006020828403121561415257600080fd5b8151612aa981613c6b565b634e487b7160e01b600052603260045260246000fd5b6000806040838503121561418657600080fd5b82516020840151909250613ea681613dbf565b64ffffffffff81811683821601908111156106ba576106ba614117565b6000602082840312156141c857600080fd5b815160ff81168114612aa957600080fd5b6000602082840312156141eb57600080fd5b5051919050565b6001600160a01b03929092168252602082015260400190565b60006020828403121561421d57600080fd5b8151612aa981613c83565b600060033d11156142415760046000803e5060005160e01c5b90565b601f8201601f191681016001600160401b038111828210171561427757634e487b7160e01b600052604160045260246000fd5b6040525050565b600060443d101561428c5790565b6040513d600319016004823e80513d60248201116001600160401b03821117156142b557505090565b80820180516001600160401b038111156142d0575050505090565b3d84016003190182820160200111156142ea575050505090565b6142f960208285010185614244565b509392505050565b60008060233d111561431d576020600460003e50506000516001905b9091565b80820281158282048414176106ba576106ba614117565b6001600160a01b038c811682528b811660208301528a166040820152606081018990526080810188905264ffffffffff87811660a083015286811660c0830152851660e082015262ffffff84166101008201526101608101836101208301526143a961014083018462ffffff169052565b9c9b505050505050505050505050565b6001600160a01b039384168152919092166020820152604081019190915260600190565b64ffffffffff82811682821603908111156106ba576106ba614117565b6001600160401b0381811683821602908116908181146108c1576108c1614117565b6001600160401b0381811683821601908111156106ba576106ba614117565b6001600160401b0382811682821603908111156106ba576106ba614117565b60006020828403121561446c57600080fd5b8151612aa981613dbf565b818103818111156106ba576106ba614117565b6000826144a757634e487b7160e01b600052601260045260246000fd5b500490565b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b600080600080600060a086880312156144f357600080fd5b85516144fe81613c6b565b60208701516040880151606089015160808a01519398509196509450925063ffffffff8116811461452e57600080fd5b80915050929550929590935056fea2646970667358221220f4cb5620249c265873c84546d63d82644401601f518f1ba5856f29a672ce5a8964736f6c634300081a0033","optimization_enabled":true,"verified_twin_address_hash":null,"is_verified":true,"compiler_settings":{"evmVersion":"paris","libraries":{},"metadata":{"bytecodeHash":"ipfs","useLiteralContent":true},"optimizer":{"enabled":true,"runs":200},"outputSelection":{"*":{"":["*"],"*":["*"]}}},"optimization_runs":200,"sourcify_repo_url":null,"decoded_constructor_args":[["0xbA3f535bbCcCcA2A154b573Ca6c5A49BAAE0a3ea",{"internalType":"address","name":"_deur","type":"address"}],["80000",{"internalType":"uint24","name":"_initialRatePPM","type":"uint24"}],["0x5C22d5b752b2121faE7F6f0069252B03B2F7c5CD",{"internalType":"address payable","name":"_roller","type":"address"}],["0x3a3985a96b1B51E6d914bc7C9e89fD6Ba6dEfE81",{"internalType":"address","name":"_factory","type":"address"}],["0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",{"internalType":"address","name":"_weth","type":"address"}]],"compiler_version":"v0.8.26+commit.8a97fa7a","is_verified_via_verifier_alliance":false,"verified_at":"2026-03-23T16:08:33.866386Z","implementations":[],"proxy_type":null,"external_libraries":[],"creation_bytecode":"0x61012060405234801561001157600080fd5b506040516148fd3803806148fd83398101604081905261003091610195565b846001600160a01b031663cd3293de6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561006e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100929190610212565b6001600160a01b03811660805260008054600160801b600160c01b03196b010000000000000000000000660100000000000064ffffffffff42811682026affffffffff000000ffffff1962ffffff8d1663010000008102919091166001600160581b031990971696909617861717918204169190910291909116600160581b600160c01b0319919091161790915560405190815285907fd76dfbd4c35cffe2a846b6488bc677c511aa4337e1551f3a360427ac7a78de7b9060200160405180910390a150506001600160a01b0394851660c05290841660a052831660e0529091166101005250610236565b6001600160a01b038116811461019257600080fd5b50565b600080600080600060a086880312156101ad57600080fd5b85516101b88161017d565b602087015190955062ffffff811681146101d157600080fd5b60408701519094506101e28161017d565b60608701519093506101f38161017d565b60808701519092506102048161017d565b809150509295509295909350565b60006020828403121561022457600080fd5b815161022f8161017d565b9392505050565b60805160a05160c05160e0516101005161457261038b60003960006106470152600081816104d301528181610ec601528181610f3801528181610fbe015281816115a80152818161161a01528181611cf101528181611d63015281816123fe0152818161244d015281816127400152818161291a01528181612f1701528181612fcb015281816137d1015281816138e701528181613aca0152613b190152600081816105c00152818161081e01528181610d2101528181610dd401528181610e47015281816112e60152818161141a015281816118f3015281816119f401528181611ba3015281816122e7015281816127900152818161282401528181612d600152818161335d01528181613412015281816134f90152818161356401528181613636015281816136e3015261375c015260008181610cf10152611aaa01526000818161049f01526106e701526145726000f3fe6080604052600436106101dc5760003560e01c80638f1d377611610102578063cb2b87b211610095578063e6ac5ea411610064578063e6ac5ea4146105f5578063e85cde6f14610615578063f09e9e3a14610635578063f32ddc2d1461066957600080fd5b8063cb2b87b21461056e578063d6d87bdb1461058e578063dbe8a4c2146105ae578063e29bf421146105e257600080fd5b8063af5806b6116100d1578063af5806b6146104f5578063b079f1631461050b578063b6f83c1714610520578063c14a9f051461055b57600080fd5b80638f1d3776146104155780639064ae7c1461046d57806391a0ac6a1461048d578063ad5c4648146104c157600080fd5b80632bf78dd81161017a578063534cb30d11610149578063534cb30d14610372578063643745fb146103aa578063664e9704146103e257806386a7c248146103f557600080fd5b80632bf78dd8146102f25780632e4b20ab1461030f57806335a4b349146103325780634e65037e1461035d57600080fd5b8063187dcc05116101b6578063187dcc05146102705780631de252e41461029257806325e28124146102b257806326a49e37146102d257600080fd5b806301ffc9a7146101e857806306a7b3761461021d5780630f2f8e861461024d57600080fd5b366101e357005b600080fd5b3480156101f457600080fd5b50610208610203366004613c41565b610689565b60405190151581526020015b60405180910390f35b34801561022957600080fd5b506000546102399062ffffff1681565b60405162ffffff9091168152602001610214565b34801561025957600080fd5b50610262600a81565b604051908152602001610214565b34801561027c57600080fd5b5061029061028b366004613c91565b6106c0565b005b34801561029e57600080fd5b506102906102ad366004613cf4565b6106d0565b3480156102be57600080fd5b506102626102cd366004613d7a565b6107f8565b3480156102de57600080fd5b506102626102ed366004613da6565b6108c8565b3480156102fe57600080fd5b50610262683635c9adc5dea0000081565b34801561031b57600080fd5b50600054610239906301000000900462ffffff1681565b610345610340366004613dd2565b6109d8565b6040516001600160a01b039091168152602001610214565b34801561036957600080fd5b5061029061110d565b34801561037e57600080fd5b5061039261038d366004613da6565b611276565b6040516001600160401b039091168152602001610214565b3480156103b657600080fd5b506102626103c5366004613e78565b600260209081526000928352604080842090915290825290205481565b3480156103ee57600080fd5b5030610345565b34801561040157600080fd5b50610262610410366004613eb1565b6112c0565b34801561042157600080fd5b50610435610430366004613da6565b611385565b604080516001600160a01b03958616815264ffffffffff94909416602085015291909316908201526060810191909152608001610214565b34801561047957600080fd5b50610290610488366004613ee8565b6113d7565b34801561049957600080fd5b506103457f000000000000000000000000000000000000000000000000000000000000000081565b3480156104cd57600080fd5b506103457f000000000000000000000000000000000000000000000000000000000000000081565b34801561050157600080fd5b50610262614e2081565b34801561051757600080fd5b506103926113e4565b34801561052c57600080fd5b5060005461054590600160301b900464ffffffffff1681565b60405164ffffffffff9091168152602001610214565b610262610569366004613f16565b6113f4565b34801561057a57600080fd5b50610290610589366004613f4b565b6118bf565b34801561059a57600080fd5b506102906105a9366004613f95565b6118d1565b3480156105ba57600080fd5b506103457f000000000000000000000000000000000000000000000000000000000000000081565b6103456105f0366004613fc1565b6119ce565b34801561060157600080fd5b50610262610610366004614028565b6120a8565b34801561062157600080fd5b50610290610630366004613e78565b6122b5565b34801561064157600080fd5b506103457f000000000000000000000000000000000000000000000000000000000000000081565b34801561067557600080fd5b50610290610684366004614045565b6122c5565b60006001600160e01b03198216630d60fedb60e21b14806106ba57506301ffc9a760e01b6001600160e01b03198316145b92915050565b6106cb8383836123cc565b505050565b60405163352e3a8360e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063352e3a8390610720903390869086906004016140b9565b60006040518083038186803b15801561073857600080fd5b505afa15801561074c573d6000803e3d6000fd5b50506000805465ffffff0000001916630100000062ffffff8816021790555061077a90504262093a8061412d565b600080546affffffffff0000000000001916600160301b64ffffffffff93841681029190911791829055604080513381526301000000840462ffffff16602082015291909204909216908201527e4964f2e48bd8a460fb41883098593956d335f36fdded4ca9cbac9252d72b2f9060600160405180910390a1505050565b60405163aa5dd7f160e01b81526001600160a01b038381166004830152600091849130917f00000000000000000000000000000000000000000000000000000000000000009091169063aa5dd7f190602401602060405180830381865afa158015610867573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061088b9190614140565b6001600160a01b0316146108b2576040516369229ba760e01b815260040160405180910390fd5b6108be848460006125a3565b91505b5092915050565b600080600183815481106108de576108de61415d565b60009182526020918290206040805160808101825260039390930290910180546001600160a01b03808216808652600160a01b90920464ffffffffff169585019590955260018201549094169183019190915260020154606082015291506109495750600092915050565b60008082604001516001600160a01b031663329864aa6040518163ffffffff1660e01b81526004016040805180830381865afa15801561098d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109b19190614173565b915091506109cf8184602001516109c89190614199565b8284612ab0565b95945050505050565b6000620f42408462ffffff161115610a035760405163b2772c5d60e01b815260040160405180910390fd5b8162ffffff16614e201180610a1f5750620f42408262ffffff16115b15610a3d57604051633a3626e360e21b815260040160405180910390fd5b60188b6001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a7d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aa191906141b6565b60ff161115610ac3576040516325dd4a5560e21b815260040160405180910390fd5b620151808564ffffffffff161015610aee5760405163fc8c61b960e01b815260040160405180910390fd5b6203f4808764ffffffffff161015610b195760405163f979252f60e01b815260040160405180910390fd5b60008b6001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b59573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b7d91906141d9565b610b8890600161412d565b60405163a9059cbb60e01b81529091506001600160a01b038d169063a9059cbb90610bbb906101239085906004016141f2565b6020604051808303816000875af1925050508015610bf6575060408051601f3d908101601f19168201909252610bf39181019061420b565b60015b610c7657610c02614228565b806308c379a003610c275750610c1661427e565b80610c215750610c40565b50610c90565b634e487b7103610c4057610c39614301565b90610c2157505b3d808015610c6a576040519150601f19603f3d011682016040523d82523d6000602084013e610c6f565b606091505b5050610c90565b506040516343befb6960e11b815260040160405180910390fd5b8a8a1015610cb157604051633a23d82560e01b815260040160405180910390fd5b700178287f49c4a1d6622fb2ab4000000000610ccd858d614321565b1015610cec57604051633a23d82560e01b815260040160405180910390fd5b5060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635d824f76337f00000000000000000000000000000000000000000000000000000000000000008f8f8e8e8e8e8e8e8e6040518c63ffffffff1660e01b8152600401610d6f9b9a99989796959493929190614338565b6020604051808303816000875af1158015610d8e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610db29190614140565b60405163b52c696d60e01b81526001600160a01b0380831660048301529192507f00000000000000000000000000000000000000000000000000000000000000009091169063b52c696d90602401600060405180830381600087803b158015610e1a57600080fd5b505af1158015610e2e573d6000803e3d6000fd5b505060405163375edc7760e11b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169250636ebdb8ee9150610e89903390683635c9adc5dea00000906004016141f2565b600060405180830381600087803b158015610ea357600080fd5b505af1158015610eb7573d6000803e3d6000fd5b505050506000341115611041577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168c6001600160a01b031614610f1657604051631a38687560e21b815260040160405180910390fd5b893414610f365760405163dd8e4af760e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015610f9157600080fd5b505af1158015610fa5573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb9250610ff8915084908e906004016141f2565b6020604051808303816000875af1158015611017573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061103b919061420b565b506110b6565b6040516323b872dd60e01b81526001600160a01b038d16906323b872dd9061107190339085908f906004016143b9565b6020604051808303816000875af1158015611090573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110b4919061420b565b505b604080516001600160a01b03808416808352908f1660208301529133917fc9b570ab9d98bdf3e38a40fd71b20edafca42449f23ca51f0bdcbf40e8ffe175910160405180910390a39b9a5050505050505050505050565b60005462ffffff63010000008204811691160361113d5760405163147fde5f60e31b815260040160405180910390fd5b600054429064ffffffffff600160301b90910481169082161015611174576040516301b3782160e21b815260040160405180910390fd5b60005462ffffff81169061119690600160581b900464ffffffffff16836143dd565b64ffffffffff166111a791906143fa565b600080546010906111c9908490600160801b90046001600160401b031661441c565b82546101009290920a6001600160401b038181021990931691909216919091021790555060008054630100000064ffffffffff60581b198216600160581b64ffffffffff8616029081179190910462ffffff166fffffffffff0000000000000000ffffff1990921662ffffff19919091161781179091556040519081527fd76dfbd4c35cffe2a846b6488bc677c511aa4337e1551f3a360427ac7a78de7b9060200160405180910390a150565b6000805462ffffff81169061129990600160581b900464ffffffffff168461443b565b6112a391906143fa565b6000546106ba9190600160801b90046001600160401b031661441c565b60405163aa5dd7f160e01b81526001600160a01b038481166004830152600091859130917f00000000000000000000000000000000000000000000000000000000000000009091169063aa5dd7f190602401602060405180830381865afa15801561132f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113539190614140565b6001600160a01b03161461137a576040516369229ba760e01b815260040160405180910390fd5b6109cf8585856125a3565b6001818154811061139557600080fd5b60009182526020909120600390910201805460018201546002909201546001600160a01b038083169450600160a01b90920464ffffffffff1692919091169084565b6106cb8383836000612b35565b60006113ef42611276565b905090565b60405163aa5dd7f160e01b81526001600160a01b038481166004830152600091859130917f00000000000000000000000000000000000000000000000000000000000000009091169063aa5dd7f190602401602060405180830381865afa158015611463573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114879190614140565b6001600160a01b0316146114ae576040516369229ba760e01b815260040160405180910390fd5b60008590506000816001600160a01b0316638ea875f36040518163ffffffff1660e01b8152600401602060405180830381865afa1580156114f3573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061151791906141d9565b90508481101561153a57604051630d57523160e11b815260040160405180910390fd5b6000826001600160a01b031663d8dfeb456040518163ffffffff1660e01b8152600401602060405180830381865afa15801561157a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061159e9190614140565b90503415611691577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316146115f857604051631a38687560e21b815260040160405180910390fd5b8634146116185760405163dd8e4af760e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561167357600080fd5b505af1158015611687573d6000803e3d6000fd5b5050505050611706565b6040516323b872dd60e01b81526001600160a01b038216906323b872dd906116c190339030908c906004016143b9565b6020604051808303816000875af11580156116e0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611704919061420b565b505b6000600180549050905060016040518060800160405280336001600160a01b031681526020014264ffffffffff168152602001866001600160a01b031681526020018a815250908060018154018082558091505060019003906000526020600020906003020160009091909190915060008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060208201518160000160146101000a81548164ffffffffff021916908364ffffffffff16021790555060408201518160010160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550606082015181600201555050836001600160a01b031663b8e2426c89856040518363ffffffff1660e01b815260040161183b929190918252602082015260400190565b600060405180830381600087803b15801561185557600080fd5b505af1158015611869573d6000803e3d6000fd5b5050604080518b8152602081018590526001600160a01b03881693503392507fc4b384b2c5ca32c8e77081f4083be594a1ea9ba34f208a9f9a458f70608585f5910160405180910390a398975050505050505050565b6118cb84848484612b35565b50505050565b60405163aa5dd7f160e01b815233600482018190529030906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063aa5dd7f190602401602060405180830381865afa15801561193a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061195e9190614140565b6001600160a01b031614611985576040516369229ba760e01b815260040160405180910390fd5b604080518581526020810185905290810183905233907f0f16da76fa675fc06a1439cf962e8f7ae36ec73aa5264a2f06fb4214b23898e29060600160405180910390a250505050565b60405163aa5dd7f160e01b81526001600160a01b038681166004830152600091879130917f00000000000000000000000000000000000000000000000000000000000000009091169063aa5dd7f190602401602060405180830381865afa158015611a3d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a619190614140565b6001600160a01b031614611a88576040516369229ba760e01b815260040160405180910390fd5b604051630167d12360e71b81526001600160a01b0388811660048301526000917f00000000000000000000000000000000000000000000000000000000000000009091169063b3e89180906024016020604051808303816000875af1158015611af5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b199190614140565b6040516336a3a4fd60e11b81526001600160a01b038a8116600483015264ffffffffff881660248301529192508291821690636d4749fa90604401600060405180830381600087803b158015611b6e57600080fd5b505af1158015611b82573d6000803e3d6000fd5b505060405163b52c696d60e01b81526001600160a01b0385811660048301527f000000000000000000000000000000000000000000000000000000000000000016925063b52c696d9150602401600060405180830381600087803b158015611be957600080fd5b505af1158015611bfd573d6000803e3d6000fd5b505050506000816001600160a01b031663d8dfeb456040518163ffffffff1660e01b8152600401602060405180830381865afa158015611c41573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c659190614140565b9050816001600160a01b031663babe7c746040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ca5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cc991906141d9565b891015611ce957604051633a23d82560e01b815260040160405180910390fd5b3415611e4c577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b031614611d4157604051631a38687560e21b815260040160405180910390fd5b883414611d615760405163dd8e4af760e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015611dbc57600080fd5b505af1158015611dd0573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b038516935063a9059cbb9250611e03915086908d906004016141f2565b6020604051808303816000875af1158015611e22573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e46919061420b565b50611ec1565b6040516323b872dd60e01b81526001600160a01b038216906323b872dd90611e7c90339087908e906004016143b9565b6020604051808303816000875af1158015611e9b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ebf919061420b565b505b604080516001600160a01b038c81168252838116602083015280861692908e16917fc9b570ab9d98bdf3e38a40fd71b20edafca42449f23ca51f0bdcbf40e8ffe175910160405180910390a36040516340c10f1960e01b81526001600160a01b038316906340c10f1990611f3b908e908c906004016141f2565b600060405180830381600087803b158015611f5557600080fd5b505af1158015611f69573d6000803e3d6000fd5b50505050600086118015611fde5750816001600160a01b031663a035b1fe6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611fb6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fda91906141d9565b8614155b1561203e5760405163395f83cf60e11b8152600481018790526001600160a01b038316906372bf079e90602401600060405180830381600087803b15801561202557600080fd5b505af1158015612039573d6000803e3d6000fd5b505050505b60405163f2fde38b60e01b81526001600160a01b038c8116600483015283169063f2fde38b90602401600060405180830381600087803b15801561208157600080fd5b505af1158015612095573d6000803e3d6000fd5b50949d9c50505050505050505050505050565b600080826001600160a01b0316638ea875f36040518163ffffffff1660e01b8152600401602060405180830381865afa1580156120e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061210d91906141d9565b90506000836001600160a01b0316634665096d6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561214f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612173919061445a565b64ffffffffff1690508042116121965761218e82600a614321565b949350505050565b6000846001600160a01b031663f3f480d96040518163ffffffff1660e01b8152600401602060405180830381865afa1580156121d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121fa919061445a565b64ffffffffff169050600061220f8342614477565b90508181116122685760006122248284614477565b90508281866122356001600a614477565b61223f9190614321565b6122499190614321565b612253919061448a565b61225d908661412d565b979650505050505050565b612273826002614321565b8110156122a957600081612288846002614321565b6122929190614477565b90508261229f8287614321565b61225d919061448a565b50600095945050505050565b6122c1828260006123cc565b5050565b60405163aa5dd7f160e01b815233600482018190529030906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063aa5dd7f190602401602060405180830381865afa15801561232e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123529190614140565b6001600160a01b031614612379576040516369229ba760e01b815260040160405180910390fd5b836001600160a01b0316336001600160a01b03167f7e020a844d0d659902f4ca7ee9c4873e8c34253de5b150c7d64258e30965191185856040516123be9291906144ac565b60405180910390a350505050565b6001600160a01b03831660009081526002602090815260408083203384529091528120805491905581801561243257507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b0316145b1561252b57604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561249957600080fd5b505af11580156124ad573d6000803e3d6000fd5b505050506000836001600160a01b03168260405160006040518083038185875af1925050503d80600081146124fe576040519150601f19603f3d011682016040523d82523d6000602084013e612503565b606091505b505090508061252557604051633d2cec6f60e21b815260040160405180910390fd5b506118cb565b60405163a9059cbb60e01b81526001600160a01b0385169063a9059cbb9061255990869085906004016141f2565b6020604051808303816000875af1158015612578573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061259c919061420b565b5050505050565b600080846001600160a01b031663d8dfeb456040518163ffffffff1660e01b8152600401602060405180830381865afa1580156125e4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126089190614140565b6040516370a0823160e01b81526001600160a01b0387811660048301529192506000918316906370a0823190602401602060405180830381865afa158015612654573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061267891906141d9565b90506000818611612689578561268b565b815b90506000612698886120a8565b90506000670de0b6b3a76400006126af8484614321565b6126b9919061448a565b905060006126c78486614477565b1180156127025750683635c9adc5dea00000670de0b6b3a76400006126ec8587614477565b6126f69085614321565b612700919061448a565b105b15612736576127118385614477565b60405163f658c6cf60e01b815260040161272d91815260200190565b60405180910390fd5b86801561277457507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316856001600160a01b0316145b156129ef576040516323b872dd60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906323b872dd906127c9903390309086906004016143b9565b6020604051808303816000875af11580156127e8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061280c919061420b565b5060405163095ea7b360e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063095ea7b39061285b908c9085906004016141f2565b6020604051808303816000875af115801561287a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061289e919061420b565b5060405163211d798360e01b815230600482015260248101849052604481018290526001600160a01b038a169063211d798390606401600060405180830381600087803b1580156128ee57600080fd5b505af1158015612902573d6000803e3d6000fd5b5050604051632e1a7d4d60e01b8152600481018690527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169250632e1a7d4d9150602401600060405180830381600087803b15801561296857600080fd5b505af115801561297c573d6000803e3d6000fd5b50506040516000925033915085908381818185875af1925050503d80600081146129c2576040519150601f19603f3d011682016040523d82523d6000602084013e6129c7565b606091505b50509050806129e957604051633d2cec6f60e21b815260040160405180910390fd5b50612a57565b60405163211d798360e01b815233600482015260248101849052604481018290526001600160a01b038a169063211d798390606401600060405180830381600087803b158015612a3e57600080fd5b505af1158015612a52573d6000803e3d6000fd5b505050505b604080516001600160a01b038b168152602081018590529081018390527f67a660133c1fb4c0bb0480a5e4a9919216684052f13f0713e88fa2fbbc81d0829060600160405180910390a1509093505050505b9392505050565b60004264ffffffffff80861690821611612acd5782915050612aa9565b612ad78486614199565b64ffffffffff168164ffffffffff1610612af5576000915050612aa9565b6000612b0186836143dd565b612b0b90866143dd565b64ffffffffff90811691508516612b228286614321565b612b2c919061448a565b92505050612aa9565b600060018581548110612b4a57612b4a61415d565b600091825260208083206040805160808101825260039490940290910180546001600160a01b038082168652600160a01b90910464ffffffffff169385019390935260018101549092168382018190526002909201546060840152805163194c325560e11b81528151939550849363329864aa926004808401939192918290030181865afa158015612be0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c049190614173565b9150915085836060015110612c195785612c1f565b82606001515b9550808360200151612c319190614199565b64ffffffffff164211612ca057612c4b8388848988612d2c565b82604001516001600160a01b03167f1eee30d91b773ac47d7485a3acb6bcd8c7c9cd8d95301b1af361baf5f0991d2e8888604051612c93929190918252602082015260400190565b60405180910390a2612d23565b612cad8388888888613188565b600080612cbb85898861328b565b9150915084604001516001600160a01b03167f7d3a26e8d43c5b70f86266bfa26c212e3c097716ff7240ccb6a9034e48754e238a83858c604051612d18949392919093845260208401929092526040830152606082015260800190565b60405180910390a250505b50505050505050565b846020015164ffffffffff164203612d4357600080fd5b84516001600160a01b03163314612e095784516001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906323b872dd903390670de0b6b3a7640000612d9c8888614321565b612da6919061448a565b6040518463ffffffff1660e01b8152600401612dc4939291906143b9565b6020604051808303816000875af1158015612de3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e07919061420b565b505b84604001516001600160a01b03166349746f10836040518263ffffffff1660e01b8152600401612e3b91815260200190565b600060405180830381600087803b158015612e5557600080fd5b505af1158015612e69573d6000803e3d6000fd5b505050508460600151821015612eb657818560600151612e899190614477565b60018581548110612e9c57612e9c61415d565b906000526020600020906003020160020181905550612f0d565b84606001518214612ec657600080fd5b60018481548110612ed957612ed961415d565b60009182526020822060039091020180546001600160c81b03191681556001810180546001600160a01b0319169055600201555b808015612fb057507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031685604001516001600160a01b031663d8dfeb456040518163ffffffff1660e01b8152600401602060405180830381865afa158015612f81573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fa59190614140565b6001600160a01b0316145b156130aa57604051632e1a7d4d60e01b8152600481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561301757600080fd5b505af115801561302b573d6000803e3d6000fd5b505050506000336001600160a01b0316836040515b60006040518083038185875af1925050503d806000811461307d576040519150601f19603f3d011682016040523d82523d6000602084013e613082565b606091505b50509050806130a457604051633d2cec6f60e21b815260040160405180910390fd5b5061259c565b84604001516001600160a01b031663d8dfeb456040518163ffffffff1660e01b8152600401602060405180830381865afa1580156130ec573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131109190614140565b6001600160a01b031663a9059cbb33846040518363ffffffff1660e01b815260040161313d9291906141f2565b6020604051808303816000875af115801561315c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613180919061420b565b505050505050565b828560600151036131de57600184815481106131a6576131a661415d565b60009182526020822060039091020180546001600160c81b03191681556001810180546001600160a01b031916905560020155613218565b82600185815481106131f2576131f261415d565b906000526020600020906003020160020160008282546132129190614477565b90915550505b61259c85604001516001600160a01b031663d8dfeb456040518163ffffffff1660e01b8152600401602060405180830381865afa15801561325d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132819190614140565b8651858585613a34565b600080600061329986613bc0565b905060008060008060008a604001516001600160a01b0316637ccd4f718b6040518263ffffffff1660e01b81526004016132d591815260200190565b60a0604051808303816000875af11580156132f4573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061331891906144db565b945094509450945094506000670de0b6b3a764000085886133399190614321565b613343919061448a565b6040516323b872dd60e01b81529091506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906323b872dd90613396903390309086906004016143b9565b6020604051808303816000875af11580156133b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133d9919061420b565b506000620f42406133ec614e2084614321565b6133f6919061448a565b8d5160405163a9059cbb60e01b81529192506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169163a9059cbb916134479185906004016141f2565b6020604051808303816000875af1158015613466573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061348a919061420b565b5060006134978284614477565b90506134a3858761412d565b81111561361b576000620f4240866134bb8985614477565b6134c59190614477565b6134d59063ffffffff8816614321565b6134df919061448a565b60405163375edc7760e11b81529091506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690636ebdb8ee9061353090309085906004016141f2565b600060405180830381600087803b15801561354a57600080fd5b505af115801561355e573d6000803e3d6000fd5b505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb8a83898b876135a09190614477565b6135aa9190614477565b6135b49190614477565b6040518363ffffffff1660e01b81526004016135d19291906141f2565b6020604051808303816000875af11580156135f0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613614919061420b565b50506136c1565b613625858761412d565b8110156136c1576001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663d1fa5e983083613667898b61412d565b6136719190614477565b6040518363ffffffff1660e01b815260040161368e9291906141f2565b600060405180830381600087803b1580156136a857600080fd5b505af11580156136bc573d6000803e3d6000fd5b505050505b6040516363b20c3360e11b81526004810187905263ffffffff851660248201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063c764186690604401600060405180830381600087803b15801561372f57600080fd5b505af1158015613743573d6000803e3d6000fd5b505060405163375edc7760e11b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169250636ebdb8ee915061379590309089906004016141f2565b600060405180830381600087803b1580156137af57600080fd5b505af11580156137c3573d6000803e3d6000fd5b505050508b801561386a57507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168e604001516001600160a01b031663d8dfeb456040518163ffffffff1660e01b8152600401602060405180830381865afa15801561383b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061385f9190614140565b6001600160a01b0316145b156139bc578d604001516001600160a01b0316631dbcff2630896040518363ffffffff1660e01b81526004016138a19291906141f2565b600060405180830381600087803b1580156138bb57600080fd5b505af11580156138cf573d6000803e3d6000fd5b5050604051632e1a7d4d60e01b8152600481018a90527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169250632e1a7d4d9150602401600060405180830381600087803b15801561393557600080fd5b505af1158015613949573d6000803e3d6000fd5b50506040516000925033915089908381818185875af1925050503d806000811461398f576040519150601f19603f3d011682016040523d82523d6000602084013e613994565b606091505b50509050806139b657604051633d2cec6f60e21b815260040160405180910390fd5b50613a21565b8d604001516001600160a01b0316631dbcff2633896040518363ffffffff1660e01b81526004016139ee9291906141f2565b600060405180830381600087803b158015613a0857600080fd5b505af1158015613a1c573d6000803e3d6000fd5b505050505b50949c909b509950505050505050505050565b8115613ac0576001600160a01b03808616600090815260026020908152604080832093881683529290529081208054859290613a7190849061412d565b92505081905550836001600160a01b03167f8dbeeabb7d576986689d0bff912a01b9736f03d95739a5603e59301a50141c5c8685604051613ab39291906141f2565b60405180910390a261259c565b808015613afe57507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316856001600160a01b0316145b15613b9257604051632e1a7d4d60e01b8152600481018490527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b158015613b6557600080fd5b505af1158015613b79573d6000803e3d6000fd5b505050506000846001600160a01b031684604051613040565b60405163a9059cbb60e01b81526001600160a01b0386169063a9059cbb9061313d90879087906004016141f2565b600080600083604001516001600160a01b031663329864aa6040518163ffffffff1660e01b81526004016040805180830381865afa158015613c06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c2a9190614173565b9150915061218e8185602001516109c89190614199565b600060208284031215613c5357600080fd5b81356001600160e01b031981168114612aa957600080fd5b6001600160a01b0381168114613c8057600080fd5b50565b8015158114613c8057600080fd5b600080600060608486031215613ca657600080fd5b8335613cb181613c6b565b92506020840135613cc181613c6b565b91506040840135613cd181613c83565b809150509250925092565b803562ffffff81168114613cef57600080fd5b919050565b600080600060408486031215613d0957600080fd5b613d1284613cdc565b925060208401356001600160401b03811115613d2d57600080fd5b8401601f81018613613d3e57600080fd5b80356001600160401b03811115613d5457600080fd5b8660208260051b8401011115613d6957600080fd5b939660209190910195509293505050565b60008060408385031215613d8d57600080fd5b8235613d9881613c6b565b946020939093013593505050565b600060208284031215613db857600080fd5b5035919050565b64ffffffffff81168114613c8057600080fd5b6000806000806000806000806000806101408b8d031215613df257600080fd5b8a35613dfd81613c6b565b995060208b0135985060408b0135975060608b0135965060808b0135613e2281613dbf565b955060a08b0135613e3281613dbf565b945060c08b0135613e4281613dbf565b9350613e5060e08c01613cdc565b92506101008b01359150613e676101208c01613cdc565b90509295989b9194979a5092959850565b60008060408385031215613e8b57600080fd5b8235613e9681613c6b565b91506020830135613ea681613c6b565b809150509250929050565b600080600060608486031215613ec657600080fd5b8335613ed181613c6b565b9250602084013591506040840135613cd181613c83565b600080600060608486031215613efd57600080fd5b83359250602084013591506040840135613cd181613c83565b600080600060608486031215613f2b57600080fd5b8335613f3681613c6b565b95602085013595506040909401359392505050565b60008060008060808587031215613f6157600080fd5b84359350602085013592506040850135613f7a81613c83565b91506060850135613f8a81613c83565b939692955090935050565b600080600060608486031215613faa57600080fd5b505081359360208301359350604090920135919050565b60008060008060008060c08789031215613fda57600080fd5b8635613fe581613c6b565b95506020870135613ff581613c6b565b94506040870135935060608701359250608087013561401381613dbf565b9598949750929591949360a090920135925050565b60006020828403121561403a57600080fd5b8135612aa981613c6b565b60008060006040848603121561405a57600080fd5b833561406581613c6b565b925060208401356001600160401b0381111561408057600080fd5b8401601f8101861361409157600080fd5b80356001600160401b038111156140a757600080fd5b866020828401011115613d6957600080fd5b6001600160a01b0384168152604060208201819052810182905260008360608301825b8581101561410c5782356140ef81613c6b565b6001600160a01b03168252602092830192909101906001016140dc565b509695505050505050565b634e487b7160e01b600052601160045260246000fd5b808201808211156106ba576106ba614117565b60006020828403121561415257600080fd5b8151612aa981613c6b565b634e487b7160e01b600052603260045260246000fd5b6000806040838503121561418657600080fd5b82516020840151909250613ea681613dbf565b64ffffffffff81811683821601908111156106ba576106ba614117565b6000602082840312156141c857600080fd5b815160ff81168114612aa957600080fd5b6000602082840312156141eb57600080fd5b5051919050565b6001600160a01b03929092168252602082015260400190565b60006020828403121561421d57600080fd5b8151612aa981613c83565b600060033d11156142415760046000803e5060005160e01c5b90565b601f8201601f191681016001600160401b038111828210171561427757634e487b7160e01b600052604160045260246000fd5b6040525050565b600060443d101561428c5790565b6040513d600319016004823e80513d60248201116001600160401b03821117156142b557505090565b80820180516001600160401b038111156142d0575050505090565b3d84016003190182820160200111156142ea575050505090565b6142f960208285010185614244565b509392505050565b60008060233d111561431d576020600460003e50506000516001905b9091565b80820281158282048414176106ba576106ba614117565b6001600160a01b038c811682528b811660208301528a166040820152606081018990526080810188905264ffffffffff87811660a083015286811660c0830152851660e082015262ffffff84166101008201526101608101836101208301526143a961014083018462ffffff169052565b9c9b505050505050505050505050565b6001600160a01b039384168152919092166020820152604081019190915260600190565b64ffffffffff82811682821603908111156106ba576106ba614117565b6001600160401b0381811683821602908116908181146108c1576108c1614117565b6001600160401b0381811683821601908111156106ba576106ba614117565b6001600160401b0382811682821603908111156106ba576106ba614117565b60006020828403121561446c57600080fd5b8151612aa981613dbf565b818103818111156106ba576106ba614117565b6000826144a757634e487b7160e01b600052601260045260246000fd5b500490565b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b600080600080600060a086880312156144f357600080fd5b85516144fe81613c6b565b60208701516040880151606089015160808a01519398509196509450925063ffffffff8116811461452e57600080fd5b80915050929550929590935056fea2646970667358221220f4cb5620249c265873c84546d63d82644401601f518f1ba5856f29a672ce5a8964736f6c634300081a0033000000000000000000000000ba3f535bbcccca2a154b573ca6c5a49baae0a3ea00000000000000000000000000000000000000000000000000000000000138800000000000000000000000005c22d5b752b2121fae7f6f0069252b03b2f7c5cd0000000000000000000000003a3985a96b1b51e6d914bc7c9e89fd6ba6defe81000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2","name":"MintingHub","is_blueprint":false,"license_type":"none","is_fully_verified":true,"is_verified_via_eth_bytecode_db":false,"language":"solidity","evm_version":"paris","can_be_visualized_via_sol2uml":true,"is_verified_via_sourcify":false,"additional_sources":[{"file_path":"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC-20 standard.\n */\ninterface IERC20Metadata is IERC20 {\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() external view returns (string memory);\n\n    /**\n     * @dev Returns the symbol of the token.\n     */\n    function symbol() external view returns (string memory);\n\n    /**\n     * @dev Returns the decimals places of the token.\n     */\n    function decimals() external view returns (uint8);\n}\n"},{"file_path":"@openzeppelin/contracts/utils/Context.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n    function _msgSender() internal view virtual returns (address) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view virtual returns (bytes calldata) {\n        return msg.data;\n    }\n\n    function _contextSuffixLength() internal view virtual returns (uint256) {\n        return 0;\n    }\n}\n"},{"file_path":"@openzeppelin/contracts/utils/introspection/ERC165.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC165} from \"./IERC165.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC-165 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 */\nabstract contract ERC165 is IERC165 {\n    /**\n     * @dev See {IERC165-supportsInterface}.\n     */\n    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n        return interfaceId == type(IERC165).interfaceId;\n    }\n}\n"},{"file_path":"@openzeppelin/contracts/utils/introspection/IERC165.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Interface of the ERC-165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[ERC].\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[ERC 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/access/Ownable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)\n\npragma solidity ^0.8.20;\n\nimport {Context} from \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * The initial owner is set to the address provided by the deployer. This can\n * later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n    address private _owner;\n\n    /**\n     * @dev The caller account is not authorized to perform an operation.\n     */\n    error OwnableUnauthorizedAccount(address account);\n\n    /**\n     * @dev The owner is not a valid owner account. (eg. `address(0)`)\n     */\n    error OwnableInvalidOwner(address owner);\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.\n     */\n    constructor(address initialOwner) {\n        if (initialOwner == address(0)) {\n            revert OwnableInvalidOwner(address(0));\n        }\n        _transferOwnership(initialOwner);\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        _checkOwner();\n        _;\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        if (owner() != _msgSender()) {\n            revert OwnableUnauthorizedAccount(_msgSender());\n        }\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby disabling any functionality that is only available to the owner.\n     */\n    function renounceOwnership() public virtual onlyOwner {\n        _transferOwnership(address(0));\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Can only be called by the current owner.\n     */\n    function transferOwnership(address newOwner) public virtual onlyOwner {\n        if (newOwner == address(0)) {\n            revert OwnableInvalidOwner(address(0));\n        }\n        _transferOwnership(newOwner);\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Internal function without access restriction.\n     */\n    function _transferOwnership(address newOwner) internal virtual {\n        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n"},{"file_path":"@openzeppelin/contracts/token/ERC20/IERC20.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Interface of the ERC-20 standard as defined in the ERC.\n */\ninterface IERC20 {\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n\n    /**\n     * @dev Returns the value of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the value of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address to, uint256 value) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n     * 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 value) external returns (bool);\n\n    /**\n     * @dev Moves a `value` amount of tokens from `from` to `to` using the\n     * allowance mechanism. `value` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n"},{"file_path":"contracts/Leadrate.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IReserve} from \"./interface/IReserve.sol\";\n\n/**\n * @title Leadrate (attempt at translating the concise German term 'Leitzins')\n *\n * A module that can provide other modules with the leading interest rate for the system.\n *\n **/\ncontract Leadrate {\n    IReserve public immutable equity;\n\n    // The following five variables are less than 256 bits, so they should be stored\n    // in the same slot, making them cheaper to access together, right?\n\n    uint24 public currentRatePPM; // 24 bits allows rates of up to ~1670% per year\n    uint24 public nextRatePPM;\n    uint40 public nextChange;\n\n    uint40 private anchorTime; // 40 bits for time in seconds spans up to 1000 human generations\n    uint64 private ticksAnchor; // in bips * seconds\n\n    event RateProposed(address who, uint24 nextRate, uint40 nextChange);\n    event RateChanged(uint24 newRate);\n\n    error NoPendingChange();\n    error ChangeNotReady();\n\n    constructor(IReserve equity_, uint24 initialRatePPM) {\n        equity = equity_;\n        nextRatePPM = initialRatePPM;\n        currentRatePPM = initialRatePPM;\n        nextChange = uint40(block.timestamp);\n        anchorTime = nextChange;\n        ticksAnchor = 0;\n        emit RateChanged(initialRatePPM); // emit for initialization indexing, if desired\n    }\n\n    /**\n     * Proposes a new interest rate that will automatically be applied after seven days.\n     * To cancel a proposal, just overwrite it with a new one proposing the current rate.\n     */\n    function proposeChange(uint24 newRatePPM_, address[] calldata helpers) external {\n        equity.checkQualified(msg.sender, helpers);\n        nextRatePPM = newRatePPM_;\n        nextChange = uint40(block.timestamp + 7 days);\n        emit RateProposed(msg.sender, nextRatePPM, nextChange);\n    }\n\n    /**\n     * Setting a previously proposed interest rate change into force.\n     */\n    function applyChange() external {\n        if (currentRatePPM == nextRatePPM) revert NoPendingChange();\n        uint40 timeNow = uint40(block.timestamp);\n        if (timeNow < nextChange) revert ChangeNotReady();\n        ticksAnchor += uint64(timeNow - anchorTime) * currentRatePPM;\n        anchorTime = timeNow;\n        currentRatePPM = nextRatePPM;\n        emit RateChanged(currentRatePPM);\n    }\n\n    /**\n     * Total accumulated 'interest ticks' since this contract was deployed.\n     * One 'tick' is a ppm-second, so one month of 12% annual interest is\n     *   120000*30*24*3600 = 311040000000 ticks.\n     * Two months of 6% annual interest would result in the same number of\n     * ticks. For simplicity, this is linear, so there is no \"interest on interest\".\n     */\n    function currentTicks() public view returns (uint64) {\n        return ticks(block.timestamp);\n    }\n\n    function ticks(uint256 timestamp) public view returns (uint64) {\n        return ticksAnchor + (uint64(timestamp) - anchorTime) * currentRatePPM;\n    }\n}\n"},{"file_path":"contracts/MintingHubV3/PositionRoller.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IDecentralizedEURO} from \"../interface/IDecentralizedEURO.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {IMintingHub} from \"./interface/IMintingHub.sol\";\nimport {IPosition} from \"./interface/IPosition.sol\";\nimport {IWrappedNative} from \"../interface/IWrappedNative.sol\";\nimport {Ownable} from \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title PositionRoller\n *\n * Helper to roll over a debt from an old position to a new one.\n * Both positions should have the same collateral. Otherwise, it does not make much sense.\n */\ncontract PositionRoller {\n    IDecentralizedEURO private deuro;\n\n    error NotOwner(address pos);\n    error NotPosition(address pos);\n    error NativeTransferFailed();\n\n    event Roll(address source, uint256 collWithdraw, uint256 repay, address target, uint256 collDeposit, uint256 mint);\n\n    constructor(address deuro_) {\n        deuro = IDecentralizedEURO(deuro_);\n    }\n\n    /**\n     * Convenience method to roll an old position into a new one.\n     *\n     * Pre-condition: an allowance for the roller to spend the collateral asset on behalf of the caller,\n     * i.e., one should set collateral.approve(roller, collateral.balanceOf(sourcePosition)).\n     *\n     * The following is assumed:\n     * - If the limit of the target position permits, the user wants to roll everything.\n     * - The user does not want to add additional collateral, but excess collateral is returned.\n     * - If not enough can be minted in the new position, it is acceptable for the roller to use dEURO from the msg.sender.\n     */\n    function rollFully(IPosition source, IPosition target) external {\n        rollFullyWithExpiration(source, target, target.expiration());\n    }\n\n    /**\n     * Like rollFully, but with a custom expiration date for the new position.\n     */\n    function rollFullyWithExpiration(IPosition source, IPosition target, uint40 expiration) public {\n        (uint256 repay, uint256 collWithdraw, uint256 mint, uint256 collDeposit) =\n            _calculateRollParams(source, target, 0);\n        roll(source, repay, collWithdraw, target, mint, collDeposit, expiration);\n    }\n\n    /**\n     * Rolls the source position into the target position using a flash loan.\n     * Both the source and the target position must recognize this roller.\n     * It is the responsibility of the caller to ensure that both positions are valid contracts.\n     *\n     * @param source The source position, must be owned by the msg.sender.\n     * @param repay The amount of principal to repay from the source position using a flash loan, freeing up some or all collateral .\n     * @param collWithdraw Collateral to move from the source position to the msg.sender.\n     * @param target The target position. If not owned by msg.sender or if it does not have the desired expiration,\n     *               it is cloned to create a position owned by the msg.sender.\n     * @param mint The amount to be minted from the target position using collateral from msg.sender.\n     * @param collDeposit The amount of collateral to be sent from msg.sender to the target position.\n     * @param expiration The desired expiration date for the target position.\n     */\n    function roll(\n        IPosition source,\n        uint256 repay,\n        uint256 collWithdraw,\n        IPosition target,\n        uint256 mint,\n        uint256 collDeposit,\n        uint40 expiration\n    ) public valid(source) valid(target) own(source) {\n        deuro.mint(address(this), repay); // take a flash loan\n        uint256 used = source.repay(repay);\n        source.withdrawCollateral(msg.sender, collWithdraw);\n        if (mint > 0) {\n            IERC20 targetCollateral = IERC20(target.collateral());\n            bool needsClone = Ownable(address(target)).owner() != msg.sender || expiration != target.expiration();\n            if (needsClone) {\n                targetCollateral.transferFrom(msg.sender, address(this), collDeposit); // get the new collateral\n                targetCollateral.approve(target.hub(), collDeposit); // approve the new collateral and clone:\n                target = _cloneTargetPosition(target, collDeposit, mint, expiration);\n            } else {\n                // We can roll into the provided existing position.\n                // We do not verify whether the target position was created by the known minting hub in order\n                // to allow positions to be rolled into future versions of the minting hub.\n                targetCollateral.transferFrom(msg.sender, address(target), collDeposit);\n                target.mint(msg.sender, mint);\n            }\n        }\n\n        // Transfer remaining flash loan to caller for repayment\n        if (repay > used) {\n            deuro.transfer(msg.sender, repay - used);\n        }\n\n        deuro.burnFrom(msg.sender, repay); // repay the flash loan\n        emit Roll(address(source), collWithdraw, repay, address(target), collDeposit, mint);\n    }\n\n    /**\n     * @notice Roll a position using native coin (ETH) as additional collateral.\n     */\n    function rollFullyNative(IPosition source, IPosition target) external payable {\n        rollFullyNativeWithExpiration(source, target, target.expiration());\n    }\n\n    function rollFullyNativeWithExpiration(IPosition source, IPosition target, uint40 expiration) public payable {\n        (uint256 repay, uint256 collWithdraw, uint256 mint, uint256 collDeposit) =\n            _calculateRollParams(source, target, msg.value);\n        rollNative(source, repay, collWithdraw, target, mint, collDeposit, expiration);\n    }\n\n    /**\n     * @notice Roll with native coin support. Wraps msg.value, withdraws source collateral to the roller,\n     * deposits to target, and returns excess as native coin.\n     */\n    function rollNative(\n        IPosition source,\n        uint256 repay,\n        uint256 collWithdraw,\n        IPosition target,\n        uint256 mint,\n        uint256 collDeposit,\n        uint40 expiration\n    ) public payable valid(source) valid(target) own(source) {\n        IERC20 collateralToken = source.collateral();\n\n        deuro.mint(address(this), repay); // take a flash loan\n        uint256 used = source.repay(repay);\n        source.withdrawCollateral(address(this), collWithdraw);\n\n        // Wrap any ETH sent as additional collateral (after flash loan to avoid idle WETH)\n        if (msg.value > 0) {\n            IWrappedNative(address(collateralToken)).deposit{value: msg.value}();\n        }\n\n        if (mint > 0) {\n            IERC20 targetCollateral = IERC20(target.collateral());\n            bool needsClone = Ownable(address(target)).owner() != msg.sender || expiration != target.expiration();\n            if (needsClone) {\n                targetCollateral.approve(target.hub(), collDeposit);\n                target = _cloneTargetPosition(target, collDeposit, mint, expiration);\n            } else {\n                targetCollateral.transfer(address(target), collDeposit);\n                target.mint(msg.sender, mint);\n            }\n        }\n\n        if (repay > used) {\n            deuro.transfer(msg.sender, repay - used);\n        }\n\n        deuro.burnFrom(msg.sender, repay); // repay the flash loan\n\n        // Return excess collateral as native coin\n        uint256 remaining = collateralToken.balanceOf(address(this));\n        if (remaining > 0) {\n            IWrappedNative(address(collateralToken)).withdraw(remaining);\n            (bool success, ) = msg.sender.call{value: remaining}(\"\");\n            if (!success) revert NativeTransferFailed();\n        }\n\n        emit Roll(address(source), collWithdraw, repay, address(target), collDeposit, mint);\n    }\n\n    function _calculateRollParams(\n        IPosition source,\n        IPosition target,\n        uint256 extraCollateral\n    ) internal view returns (uint256 repay, uint256 collWithdraw, uint256 mint, uint256 collDeposit) {\n        require(source.collateral() == target.collateral());\n        uint256 principal = source.principal();\n        uint256 interest = source.getInterest();\n        uint256 usableMint = source.getUsableMint(principal) + interest;\n        uint256 mintAmount = target.getMintAmount(usableMint);\n        uint256 collateralAvailable = IERC20(source.collateral()).balanceOf(address(source));\n        uint256 totalAvailable = collateralAvailable + extraCollateral;\n        uint256 targetPrice = target.price();\n        uint256 depositAmount = (mintAmount * 10 ** 18 + targetPrice - 1) / targetPrice;\n        if (depositAmount > totalAvailable) {\n            depositAmount = totalAvailable;\n            mintAmount = (depositAmount * targetPrice) / 10 ** 18;\n        }\n        repay = principal + interest;\n        collWithdraw = collateralAvailable;\n        mint = mintAmount;\n        collDeposit = depositAmount;\n    }\n\n    /**\n     * Clones the target position and mints the specified amount using the given collateral.\n     */\n    function _cloneTargetPosition(\n        IPosition target,\n        uint256 collDeposit,\n        uint256 mint,\n        uint40 expiration\n    ) internal returns (IPosition) {\n        return IPosition(\n            IMintingHub(target.hub()).clone(msg.sender, address(target), collDeposit, mint, expiration, 0)\n        );\n    }\n\n    modifier own(IPosition pos) {\n        if (Ownable(address(pos)).owner() != msg.sender) revert NotOwner(address(pos));\n        _;\n    }\n\n    modifier valid(IPosition pos) {\n        if (deuro.getPositionParent(address(pos)) == address(0x0)) revert NotPosition(address(pos));\n        _;\n    }\n\n    /**\n     * @dev Required for WETH.withdraw() callbacks and receiving excess native coin.\n     */\n    receive() external payable {}\n}\n"},{"file_path":"contracts/MintingHubV3/interface/IMintingHub.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.10;\n\nimport {ILeadrate} from \"../../interface/ILeadrate.sol\";\nimport {IPosition} from \"./IPosition.sol\";\nimport {PositionRoller} from \"../PositionRoller.sol\";\n\ninterface IMintingHub {\n    // Events for centralized position monitoring (emitted by hub, not individual positions)\n    event PositionUpdate(address indexed position, uint256 collateral, uint256 price, uint256 principal);\n\n    event PositionDeniedByGovernance(address indexed position, address indexed denier, string message);\n\n    function RATE() external view returns (ILeadrate);\n\n    function ROLLER() external view returns (PositionRoller);\n\n    function WETH() external view returns (address);\n\n    // Position event forwarding functions\n    function emitPositionUpdate(uint256 collateral, uint256 price, uint256 principal) external;\n\n    function emitPositionDenied(address denier, string calldata message) external;\n\n    function challenge(\n        address _positionAddr,\n        uint256 _collateralAmount,\n        uint256 minimumPrice\n    ) external payable returns (uint256);\n\n    function bid(uint256 _challengeNumber, uint256 size, bool postponeCollateralReturn) external;\n\n    function bid(\n        uint256 _challengeNumber,\n        uint256 size,\n        bool postponeCollateralReturn,\n        bool returnCollateralAsNative\n    ) external;\n\n    function returnPostponedCollateral(address collateral, address target) external;\n\n    function returnPostponedCollateral(address collateral, address target, bool asNative) external;\n\n    function buyExpiredCollateral(IPosition pos, uint256 upToAmount) external returns (uint256);\n\n    function buyExpiredCollateral(IPosition pos, uint256 upToAmount, bool receiveAsNative) external returns (uint256);\n\n    function clone(\n        address owner,\n        address parent,\n        uint256 _initialCollateral,\n        uint256 _initialMint,\n        uint40 expiration,\n        uint256 _liqPrice\n    ) external payable returns (address);\n}\n"},{"file_path":"contracts/MintingHubV3/interface/IPosition.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\ninterface IPosition {\n    function hub() external view returns (address);\n\n    function collateral() external view returns (IERC20);\n\n    function minimumCollateral() external view returns (uint256);\n\n    function price() external view returns (uint256);\n\n    function virtualPrice() external view returns (uint256);\n\n    function challengedAmount() external view returns (uint256);\n\n    function original() external view returns (address payable);\n\n    function expiration() external view returns (uint40);\n\n    function cooldown() external view returns (uint40);\n\n    function limit() external view returns (uint256);\n\n    function challengePeriod() external view returns (uint40);\n\n    function start() external view returns (uint40);\n\n    function riskPremiumPPM() external view returns (uint24);\n\n    function reserveContribution() external view returns (uint24);\n\n    function principal() external view returns (uint256);\n\n    function interest() external view returns (uint256);\n\n    function lastAccrual() external view returns (uint40);\n\n    function initialize(address parent, uint40 _expiration) external;\n\n    function assertCloneable() external;\n\n    function notifyMint(uint256 mint_) external;\n\n    function notifyRepaid(uint256 repaid_) external;\n\n    function availableForClones() external view returns (uint256);\n\n    function availableForMinting() external view returns (uint256);\n\n    function deny(address[] calldata helpers, string calldata message) external;\n\n    function getUsableMint(uint256 totalMint) external view returns (uint256);\n\n    function getMintAmount(uint256 usableMint) external view returns (uint256);\n\n    function adjust(uint256 newPrincipal, uint256 newCollateral, uint256 newPrice, bool withdrawAsNative) external payable;\n\n    function adjustPrice(uint256 newPrice) external;\n\n    function adjustPriceWithReference(uint256 newPrice, address referencePosition) external;\n\n    function adjustWithReference(uint256 newPrincipal, uint256 newCollateral, uint256 newPrice, address referencePosition, bool withdrawAsNative) external payable;\n\n    function isValidPriceReference(address referencePosition, uint256 newPrice) external view returns (bool);\n\n    function isClosed() external view returns (bool);\n\n    function mint(address target, uint256 amount) external;\n\n    function getDebt() external view returns (uint256);\n\n    function getInterest() external view returns (uint256);\n\n    function repay(uint256 amount) external returns (uint256);\n\n    function repayFull() external returns (uint256);\n\n    function forceSale(address buyer, uint256 colAmount, uint256 proceeds) external;\n\n    function rescueToken(address token, address target, uint256 amount) external;\n\n    function withdrawCollateral(address target, uint256 amount) external;\n\n    function withdrawCollateralAsNative(address target, uint256 amount) external;\n\n    function transferChallengedCollateral(address target, uint256 amount) external;\n\n    function challengeData() external view returns (uint256 liqPrice, uint40 phase);\n\n    function notifyChallengeStarted(uint256 size, uint256 _price) external;\n\n    function notifyChallengeAverted(uint256 size) external;\n\n    function notifyChallengeSucceeded(\n        uint256 _size\n    ) external returns (address, uint256, uint256, uint256, uint32);\n}\n"},{"file_path":"contracts/MintingHubV3/interface/IPositionFactory.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IPositionFactory {\n    function createNewPosition(\n        address _owner,\n        address _deuro,\n        address _collateral,\n        uint256 _minCollateral,\n        uint256 _initialLimit,\n        uint40 _initPeriod,\n        uint40 _duration,\n        uint40 _challengePeriod,\n        uint24 _riskPremiumPPM,\n        uint256 _liqPrice,\n        uint24 _reserve\n    ) external returns (address);\n\n    function clonePosition(address _parent) external returns (address);\n}\n"},{"file_path":"contracts/interface/IDecentralizedEURO.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IReserve} from \"./IReserve.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\ninterface IDecentralizedEURO is IERC20 {\n    function suggestMinter(\n        address _minter,\n        uint256 _applicationPeriod,\n        uint256 _applicationFee,\n        string calldata _message\n    ) external;\n\n    function registerPosition(address position) external;\n\n    function denyMinter(address minter, address[] calldata helpers, string calldata message) external;\n\n    function reserve() external view returns (IReserve);\n\n    function minterReserve() external view returns (uint256);\n\n    function calculateAssignedReserve(uint256 mintedAmount, uint32 _reservePPM) external view returns (uint256);\n\n    function calculateFreedAmount(uint256 amountExcludingReserve, uint32 _reservePPM) external view returns (uint256);\n\n    function equity() external view returns (uint256);\n\n    function isMinter(address minter) external view returns (bool);\n\n    function getPositionParent(address position) external view returns (address);\n\n    function mint(address target, uint256 amount) external;\n\n    function mintWithReserve(address target, uint256 amount, uint32 reservePPM) external;\n\n    function burn(uint256 amount) external;\n\n    function burnFrom(address target, uint256 amount) external;\n\n    function burnWithoutReserve(uint256 amount, uint32 reservePPM) external;\n\n    function burnFromWithReserve(\n        address payer,\n        uint256 targetTotalBurnAmount,\n        uint32 reservePPM\n    ) external returns (uint256);\n\n    function coverLoss(address source, uint256 amount) external;\n\n    function distributeProfits(address recipient, uint256 amount) external;\n\n    function collectProfits(address source, uint256 _amount) external;\n}\n"},{"file_path":"contracts/interface/ILeadrate.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface ILeadrate {\n   function currentRatePPM() external view returns (uint24);\n   function currentTicks() external view returns (uint64);\n}"},{"file_path":"contracts/interface/IReserve.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\ninterface IReserve is IERC20 {\n    function invest(uint256 amount, uint256 expected) external returns (uint256);\n    function checkQualified(address sender, address[] calldata helpers) external view;\n    function votesDelegated(address sender, address[] calldata helpers) external view returns (uint256);\n    function totalVotes() external view returns (uint256);\n}\n"},{"file_path":"contracts/interface/IWrappedNative.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IWrappedNative {\n    function deposit() external payable;\n    function withdraw(uint256) external;\n}\n"}],"certified":false,"conflicting_implementations":null,"abi":[{"inputs":[{"internalType":"address","name":"_deur","type":"address"},{"internalType":"uint24","name":"_initialRatePPM","type":"uint24"},{"internalType":"address payable","name":"_roller","type":"address"},{"internalType":"address","name":"_factory","type":"address"},{"internalType":"address","name":"_weth","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ChallengeTimeTooShort","type":"error"},{"inputs":[],"name":"ChangeNotReady","type":"error"},{"inputs":[],"name":"IncompatibleCollateral","type":"error"},{"inputs":[],"name":"InitPeriodTooShort","type":"error"},{"inputs":[],"name":"InsufficientCollateral","type":"error"},{"inputs":[],"name":"InvalidCollateralDecimals","type":"error"},{"inputs":[],"name":"InvalidPos","type":"error"},{"inputs":[],"name":"InvalidReservePPM","type":"error"},{"inputs":[],"name":"InvalidRiskPremium","type":"error"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"LeaveNoDust","type":"error"},{"inputs":[],"name":"NativeOnlyForWETH","type":"error"},{"inputs":[],"name":"NativeTransferFailed","type":"error"},{"inputs":[],"name":"NoPendingChange","type":"error"},{"inputs":[],"name":"UnexpectedPrice","type":"error"},{"inputs":[],"name":"ValueMismatch","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"position","type":"address"},{"indexed":false,"internalType":"uint256","name":"number","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"size","type":"uint256"}],"name":"ChallengeAverted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"challenger","type":"address"},{"indexed":true,"internalType":"address","name":"position","type":"address"},{"indexed":false,"internalType":"uint256","name":"size","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"number","type":"uint256"}],"name":"ChallengeStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"position","type":"address"},{"indexed":false,"internalType":"uint256","name":"number","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"bid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"acquiredCollateral","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"challengeSize","type":"uint256"}],"name":"ChallengeSucceeded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"pos","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"priceE36MinusDecimals","type":"uint256"}],"name":"ForcedSale","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"position","type":"address"},{"indexed":true,"internalType":"address","name":"denier","type":"address"},{"indexed":false,"internalType":"string","name":"message","type":"string"}],"name":"PositionDeniedByGovernance","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"position","type":"address"},{"indexed":false,"internalType":"address","name":"original","type":"address"},{"indexed":false,"internalType":"address","name":"collateral","type":"address"}],"name":"PositionOpened","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"position","type":"address"},{"indexed":false,"internalType":"uint256","name":"collateral","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"principal","type":"uint256"}],"name":"PositionUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"collateral","type":"address"},{"indexed":true,"internalType":"address","name":"beneficiary","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"PostponedReturn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint24","name":"newRate","type":"uint24"}],"name":"RateChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"who","type":"address"},{"indexed":false,"internalType":"uint24","name":"nextRate","type":"uint24"},{"indexed":false,"internalType":"uint40","name":"nextChange","type":"uint40"}],"name":"RateProposed","type":"event"},{"inputs":[],"name":"CHALLENGER_REWARD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEURO","outputs":[{"internalType":"contract IDecentralizedEURO","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EXPIRED_PRICE_FACTOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"OPENING_FEE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RATE","outputs":[{"internalType":"contract ILeadrate","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ROLLER","outputs":[{"internalType":"contract PositionRoller","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"applyChange","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_challengeNumber","type":"uint256"},{"internalType":"uint256","name":"size","type":"uint256"},{"internalType":"bool","name":"postponeCollateralReturn","type":"bool"}],"name":"bid","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_challengeNumber","type":"uint256"},{"internalType":"uint256","name":"size","type":"uint256"},{"internalType":"bool","name":"postponeCollateralReturn","type":"bool"},{"internalType":"bool","name":"returnCollateralAsNative","type":"bool"}],"name":"bid","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IPosition","name":"pos","type":"address"},{"internalType":"uint256","name":"upToAmount","type":"uint256"}],"name":"buyExpiredCollateral","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IPosition","name":"pos","type":"address"},{"internalType":"uint256","name":"upToAmount","type":"uint256"},{"internalType":"bool","name":"receiveAsNative","type":"bool"}],"name":"buyExpiredCollateral","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_positionAddr","type":"address"},{"internalType":"uint256","name":"_collateralAmount","type":"uint256"},{"internalType":"uint256","name":"minimumPrice","type":"uint256"}],"name":"challenge","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"challenges","outputs":[{"internalType":"address","name":"challenger","type":"address"},{"internalType":"uint40","name":"start","type":"uint40"},{"internalType":"contract IPosition","name":"position","type":"address"},{"internalType":"uint256","name":"size","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"parent","type":"address"},{"internalType":"uint256","name":"_initialCollateral","type":"uint256"},{"internalType":"uint256","name":"_initialMint","type":"uint256"},{"internalType":"uint40","name":"expiration","type":"uint40"},{"internalType":"uint256","name":"_liqPrice","type":"uint256"}],"name":"clone","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"currentRatePPM","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentTicks","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"denier","type":"address"},{"internalType":"string","name":"message","type":"string"}],"name":"emitPositionDenied","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_collateral","type":"uint256"},{"internalType":"uint256","name":"_price","type":"uint256"},{"internalType":"uint256","name":"_principal","type":"uint256"}],"name":"emitPositionUpdate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"equity","outputs":[{"internalType":"contract IReserve","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IPosition","name":"pos","type":"address"}],"name":"expiredPurchasePrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextChange","outputs":[{"internalType":"uint40","name":"","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextRatePPM","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_collateralAddress","type":"address"},{"internalType":"uint256","name":"_minCollateral","type":"uint256"},{"internalType":"uint256","name":"_initialCollateral","type":"uint256"},{"internalType":"uint256","name":"_mintingMaximum","type":"uint256"},{"internalType":"uint40","name":"_initPeriodSeconds","type":"uint40"},{"internalType":"uint40","name":"_expirationSeconds","type":"uint40"},{"internalType":"uint40","name":"_challengeSeconds","type":"uint40"},{"internalType":"uint24","name":"_riskPremium","type":"uint24"},{"internalType":"uint256","name":"_liqPrice","type":"uint256"},{"internalType":"uint24","name":"_reservePPM","type":"uint24"}],"name":"openPosition","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"collateral","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"pendingReturns","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"challengeNumber","type":"uint256"}],"name":"price","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint24","name":"newRatePPM_","type":"uint24"},{"internalType":"address[]","name":"helpers","type":"address[]"}],"name":"proposeChange","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"collateral","type":"address"},{"internalType":"address","name":"target","type":"address"},{"internalType":"bool","name":"asNative","type":"bool"}],"name":"returnPostponedCollateral","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"collateral","type":"address"},{"internalType":"address","name":"target","type":"address"}],"name":"returnPostponedCollateral","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":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"ticks","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}],"is_changed_bytecode":false,"is_partially_verified":false,"constructor_args":"0x000000000000000000000000ba3f535bbcccca2a154b573ca6c5a49baae0a3ea00000000000000000000000000000000000000000000000000000000000138800000000000000000000000005c22d5b752b2121fae7f6f0069252b03b2f7c5cd0000000000000000000000003a3985a96b1b51e6d914bc7c9e89fd6ba6defe81000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"}