{"file_path":"contracts/MintingHubV3/PositionRoller.sol","creation_status":"success","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJuiceDollar} from \"../interface/IJuiceDollar.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 *\n * For standard ERC20 positions, use roll/rollFully/rollFullyWithExpiration.\n * Collateral flows through the user's wallet and requires approval.\n *\n * For native coin positions (e.g., WCBTC), use rollNative/rollFullyNative/rollFullyNativeWithExpiration.\n * Collateral flows through the roller, no approval needed, and excess is returned as native coin.\n */\ncontract PositionRoller {\n    IJuiceDollar private jusd;\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 jusd_) {\n        jusd = IJuiceDollar(jusd_);\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\n     * on behalf of the caller, i.e., 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 JUSD 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) = _calculateRollParams(\n            source,\n            target,\n            0\n        );\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.\n     * @param collWithdraw Collateral to withdraw from the source position.\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.\n     * @param collDeposit The amount of collateral to deposit into 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        jusd.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);\n                targetCollateral.approve(target.hub(), collDeposit);\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            jusd.transfer(msg.sender, repay - used);\n        }\n\n        jusd.burnFrom(msg.sender, repay); // repay the flash loan\n        emit Roll(address(source), collWithdraw, repay, address(target), collDeposit, mint);\n    }\n\n    /**\n     * Convenience method to roll a native coin position into a new one.\n     *\n     * No collateral approval is needed - collateral flows through the roller\n     * and excess is returned as native coin.\n     *\n     * Additional collateral can be provided via msg.value.\n     */\n    function rollFullyNative(IPosition source, IPosition target) external payable {\n        rollFullyNativeWithExpiration(source, target, target.expiration());\n    }\n\n    /**\n     * Like rollFullyNative, but with a custom expiration date for the new position.\n     */\n    function rollFullyNativeWithExpiration(IPosition source, IPosition target, uint40 expiration) public payable {\n        (uint256 repay, uint256 collWithdraw, uint256 mint, uint256 collDeposit) = _calculateRollParams(\n            source,\n            target,\n            msg.value\n        );\n        rollNative(source, repay, collWithdraw, target, mint, collDeposit, expiration);\n    }\n\n    /**\n     * Rolls a native coin position into the target position using a flash loan.\n     * Collateral is routed through the roller and returned as native coin,\n     * eliminating the need for users to interact with wrapped native tokens directly.\n     *\n     * If additional collateral is needed (collDeposit > collWithdraw), it can be provided\n     * as native coin via msg.value.\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.\n     * @param collWithdraw Collateral to withdraw from the source position.\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.\n     * @param collDeposit The amount of collateral to deposit into the target position.\n     * @param expiration The desired expiration date for the target position.\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        jusd.mint(address(this), repay); // take a flash loan\n        uint256 used = source.repay(repay);\n        source.withdrawCollateral(address(this), collWithdraw);\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        // Transfer remaining flash loan to caller for repayment\n        if (repay > used) {\n            jusd.transfer(msg.sender, repay - used);\n        }\n        jusd.burnFrom(msg.sender, repay); // repay the flash loan\n\n        // Return excess 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    /**\n     * Calculates the parameters for a roll operation.\n     * @param extraCollateral Additional collateral provided via msg.value (for native rolls).\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\n            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 (jusd.getPositionParent(address(pos)) == address(0x0)) revert NotPosition(address(pos));\n        _;\n    }\n\n    /// @notice Required to receive native coin when unwrapping\n    receive() external payable {}\n}\n","deployed_bytecode":"0x6080604052600436106100595760003560e01c80635e871b541461006557806384a2496b1461008757806389523c331461009a578063b227696b146100ba578063b7daf954146100cd578063c2a1c506146100e057600080fd5b3661006057005b600080fd5b34801561007157600080fd5b5061008561008036600461192d565b610100565b005b610085610095366004611978565b610132565b3480156100a657600080fd5b506100856100b53660046119b1565b61019d565b6100856100c83660046119b1565b610998565b6100856100db36600461192d565b611308565b3480156100ec57600080fd5b506100856100fb366004611978565b611330565b60008060008061011287876000611397565b93509350935093506101298785858986868b61019d565b50505050505050565b6101998282836001600160a01b0316634665096d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610175573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100db9190611a23565b5050565b6000805460405163aa5dd7f160e01b81526001600160a01b03808b1660048301528a9392169063aa5dd7f190602401602060405180830381865afa1580156101e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061020d9190611a47565b6001600160a01b03160361024457604051631a71b9a760e01b81526001600160a01b03821660048201526024015b60405180910390fd5b6000805460405163aa5dd7f160e01b81526001600160a01b038089166004830152889392169063aa5dd7f190602401602060405180830381865afa158015610290573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102b49190611a47565b6001600160a01b0316036102e657604051631a71b9a760e01b81526001600160a01b038216600482015260240161023b565b88336001600160a01b0316816001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561032f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103539190611a47565b6001600160a01b0316146103855760405163245aecd360e01b81526001600160a01b038216600482015260240161023b565b6000546040516340c10f1960e01b81526001600160a01b03909116906340c10f19906103b79030908d90600401611a64565b600060405180830381600087803b1580156103d157600080fd5b505af11580156103e5573d6000803e3d6000fd5b5050604051631b8fec7360e11b8152600481018c9052600092506001600160a01b038d16915063371fd8e6906024016020604051808303816000875af1158015610433573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104579190611a7d565b60405163350c35e960e01b81529091506001600160a01b038c169063350c35e9906104889033908d90600401611a64565b600060405180830381600087803b1580156104a257600080fd5b505af11580156104b6573d6000803e3d6000fd5b505050506000871115610860576000886001600160a01b031663d8dfeb456040518163ffffffff1660e01b8152600401602060405180830381865afa158015610503573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105279190611a47565b90506000336001600160a01b03168a6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610573573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105979190611a47565b6001600160a01b031614158061061c5750896001600160a01b0316634665096d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061060a9190611a23565b64ffffffffff168764ffffffffff1614155b90508015610782576040516323b872dd60e01b8152336004820152306024820152604481018990526001600160a01b038316906323b872dd906064016020604051808303816000875af1158015610677573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061069b9190611a96565b50816001600160a01b031663095ea7b38b6001600160a01b031663365a86fc6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156106e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061070d9190611a47565b8a6040518363ffffffff1660e01b815260040161072b929190611a64565b6020604051808303816000875af115801561074a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061076e9190611a96565b5061077b8a898b8a6117ff565b995061085d565b6040516323b872dd60e01b81523360048201526001600160a01b038b81166024830152604482018a90528316906323b872dd906064016020604051808303816000875af11580156107d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107fb9190611a96565b506040516340c10f1960e01b81526001600160a01b038b16906340c10f199061082a9033908d90600401611a64565b600060405180830381600087803b15801561084457600080fd5b505af1158015610858573d6000803e3d6000fd5b505050505b50505b808a11156108e6576000546001600160a01b031663a9059cbb33610884848e611ace565b6040518363ffffffff1660e01b81526004016108a1929190611a64565b6020604051808303816000875af11580156108c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108e49190611a96565b505b60005460405163079cc67960e41b81526001600160a01b03909116906379cc6790906109189033908e90600401611a64565b600060405180830381600087803b15801561093257600080fd5b505af1158015610946573d6000803e3d6000fd5b505050507f8ba6e48d27ab46e18ba0971bb468a2e47a7fac577d846de107eb2fe948c2f5958b8a8c8b8a8c60405161098396959493929190611ae7565b60405180910390a15050505050505050505050565b6000805460405163aa5dd7f160e01b81526001600160a01b03808b1660048301528a9392169063aa5dd7f190602401602060405180830381865afa1580156109e4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a089190611a47565b6001600160a01b031603610a3a57604051631a71b9a760e01b81526001600160a01b038216600482015260240161023b565b6000805460405163aa5dd7f160e01b81526001600160a01b038089166004830152889392169063aa5dd7f190602401602060405180830381865afa158015610a86573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aaa9190611a47565b6001600160a01b031603610adc57604051631a71b9a760e01b81526001600160a01b038216600482015260240161023b565b88336001600160a01b0316816001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b25573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b499190611a47565b6001600160a01b031614610b7b5760405163245aecd360e01b81526001600160a01b038216600482015260240161023b565b60008a6001600160a01b031663d8dfeb456040518163ffffffff1660e01b8152600401602060405180830381865afa158015610bbb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bdf9190611a47565b6000546040516340c10f1960e01b81529192506001600160a01b0316906340c10f1990610c129030908e90600401611a64565b600060405180830381600087803b158015610c2c57600080fd5b505af1158015610c40573d6000803e3d6000fd5b5050604051631b8fec7360e11b8152600481018d9052600092506001600160a01b038e16915063371fd8e6906024016020604051808303816000875af1158015610c8e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cb29190611a7d565b60405163350c35e960e01b81529091506001600160a01b038d169063350c35e990610ce39030908e90600401611a64565b600060405180830381600087803b158015610cfd57600080fd5b505af1158015610d11573d6000803e3d6000fd5b505050506000341115610d7357816001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015610d5957600080fd5b505af1158015610d6d573d6000803e3d6000fd5b50505050505b8715611096576000896001600160a01b031663d8dfeb456040518163ffffffff1660e01b8152600401602060405180830381865afa158015610db9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ddd9190611a47565b90506000336001600160a01b03168b6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e29573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e4d9190611a47565b6001600160a01b0316141580610ed257508a6001600160a01b0316634665096d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e9c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ec09190611a23565b64ffffffffff168864ffffffffff1614155b90508015610fc057816001600160a01b031663095ea7b38c6001600160a01b031663365a86fc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f27573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f4b9190611a47565b8b6040518363ffffffff1660e01b8152600401610f69929190611a64565b6020604051808303816000875af1158015610f88573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fac9190611a96565b50610fb98b8a8c8b6117ff565b9a50611093565b60405163a9059cbb60e01b81526001600160a01b0383169063a9059cbb90610fee908e908d90600401611a64565b6020604051808303816000875af115801561100d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110319190611a96565b506040516340c10f1960e01b81526001600160a01b038c16906340c10f19906110609033908e90600401611a64565b600060405180830381600087803b15801561107a57600080fd5b505af115801561108e573d6000803e3d6000fd5b505050505b50505b808b111561111c576000546001600160a01b031663a9059cbb336110ba848f611ace565b6040518363ffffffff1660e01b81526004016110d7929190611a64565b6020604051808303816000875af11580156110f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061111a9190611a96565b505b60005460405163079cc67960e41b81526001600160a01b03909116906379cc67909061114e9033908f90600401611a64565b600060405180830381600087803b15801561116857600080fd5b505af115801561117c573d6000803e3d6000fd5b50506040516370a0823160e01b8152306004820152600092506001600160a01b03851691506370a0823190602401602060405180830381865afa1580156111c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111eb9190611a7d565b905080156112b857604051632e1a7d4d60e01b8152600481018290526001600160a01b03841690632e1a7d4d90602401600060405180830381600087803b15801561123557600080fd5b505af1158015611249573d6000803e3d6000fd5b50506040516000925033915083908381818185875af1925050503d806000811461128f576040519150601f19603f3d011682016040523d82523d6000602084013e611294565b606091505b50509050806112b657604051633d2cec6f60e21b815260040160405180910390fd5b505b7f8ba6e48d27ab46e18ba0971bb468a2e47a7fac577d846de107eb2fe948c2f5958d8c8e8d8c8e6040516112f196959493929190611ae7565b60405180910390a150505050505050505050505050565b600080600080611319878734611397565b93509350935093506101298785858986868b610998565b6101998282836001600160a01b0316634665096d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611373573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100809190611a23565b600080600080856001600160a01b031663d8dfeb456040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113ff9190611a47565b6001600160a01b0316876001600160a01b031663d8dfeb456040518163ffffffff1660e01b8152600401602060405180830381865afa158015611446573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061146a9190611a47565b6001600160a01b03161461147d57600080fd5b6000876001600160a01b031663ba5d30786040518163ffffffff1660e01b8152600401602060405180830381865afa1580156114bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114e19190611a7d565b90506000886001600160a01b031663e5a4bed36040518163ffffffff1660e01b8152600401602060405180830381865afa158015611523573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115479190611a7d565b90506000818a6001600160a01b031663c54a89ca856040518263ffffffff1660e01b815260040161157a91815260200190565b602060405180830381865afa158015611597573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115bb9190611a7d565b6115c59190611b21565b604051634ef17bcb60e11b8152600481018290529091506000906001600160a01b038b1690639de2f79690602401602060405180830381865afa158015611610573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116349190611a7d565b905060008b6001600160a01b031663d8dfeb456040518163ffffffff1660e01b8152600401602060405180830381865afa158015611676573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061169a9190611a47565b6040516370a0823160e01b81526001600160a01b038e8116600483015291909116906370a0823190602401602060405180830381865afa1580156116e2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117069190611a7d565b905060006117148b83611b21565b905060008c6001600160a01b031663a035b1fe6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611756573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061177a9190611a7d565b905060008160018161179488670de0b6b3a7640000611b34565b61179e9190611b21565b6117a89190611ace565b6117b29190611b4b565b9050828111156117de575081670de0b6b3a76400006117d18383611b34565b6117db9190611b4b565b94505b6117e88789611b21565b9f939e50939c50929a509098505050505050505050565b6000846001600160a01b031663365a86fc6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561183f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118639190611a47565b60405163e29bf42160e01b81523360048201526001600160a01b038781166024830152604482018790526064820186905264ffffffffff85166084830152600060a4830152919091169063e29bf4219060c4016020604051808303816000875af11580156118d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118f99190611a47565b95945050505050565b6001600160a01b038116811461191757600080fd5b50565b64ffffffffff8116811461191757600080fd5b60008060006060848603121561194257600080fd5b833561194d81611902565b9250602084013561195d81611902565b9150604084013561196d8161191a565b809150509250925092565b6000806040838503121561198b57600080fd5b823561199681611902565b915060208301356119a681611902565b809150509250929050565b600080600080600080600060e0888a0312156119cc57600080fd5b87356119d781611902565b9650602088013595506040880135945060608801356119f581611902565b93506080880135925060a0880135915060c0880135611a138161191a565b8091505092959891949750929550565b600060208284031215611a3557600080fd5b8151611a408161191a565b9392505050565b600060208284031215611a5957600080fd5b8151611a4081611902565b6001600160a01b03929092168252602082015260400190565b600060208284031215611a8f57600080fd5b5051919050565b600060208284031215611aa857600080fd5b81518015158114611a4057600080fd5b634e487b7160e01b600052601160045260246000fd5b81810381811115611ae157611ae1611ab8565b92915050565b6001600160a01b0396871681526020810195909552604085019390935293166060830152608082019290925260a081019190915260c00190565b80820180821115611ae157611ae1611ab8565b8082028115828204841417611ae157611ae1611ab8565b600082611b6857634e487b7160e01b600052601260045260246000fd5b50049056fea2646970667358221220b01cc7f8fabff5de6e955c29c8eb0a66f2a1af23a26629d3a49e7a30905a86f864736f6c634300081a0033","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":"jusd_","type":"address"}]],"compiler_version":"v0.8.26+commit.8a97fa7a","is_verified_via_verifier_alliance":false,"verified_at":"2026-03-23T15:40:44.235689Z","implementations":[],"proxy_type":null,"external_libraries":[],"creation_bytecode":"0x6080604052348015600f57600080fd5b50604051611c30380380611c30833981016040819052602c916050565b600080546001600160a01b0319166001600160a01b0392909216919091179055607e565b600060208284031215606157600080fd5b81516001600160a01b0381168114607757600080fd5b9392505050565b611ba38061008d6000396000f3fe6080604052600436106100595760003560e01c80635e871b541461006557806384a2496b1461008757806389523c331461009a578063b227696b146100ba578063b7daf954146100cd578063c2a1c506146100e057600080fd5b3661006057005b600080fd5b34801561007157600080fd5b5061008561008036600461192d565b610100565b005b610085610095366004611978565b610132565b3480156100a657600080fd5b506100856100b53660046119b1565b61019d565b6100856100c83660046119b1565b610998565b6100856100db36600461192d565b611308565b3480156100ec57600080fd5b506100856100fb366004611978565b611330565b60008060008061011287876000611397565b93509350935093506101298785858986868b61019d565b50505050505050565b6101998282836001600160a01b0316634665096d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610175573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100db9190611a23565b5050565b6000805460405163aa5dd7f160e01b81526001600160a01b03808b1660048301528a9392169063aa5dd7f190602401602060405180830381865afa1580156101e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061020d9190611a47565b6001600160a01b03160361024457604051631a71b9a760e01b81526001600160a01b03821660048201526024015b60405180910390fd5b6000805460405163aa5dd7f160e01b81526001600160a01b038089166004830152889392169063aa5dd7f190602401602060405180830381865afa158015610290573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102b49190611a47565b6001600160a01b0316036102e657604051631a71b9a760e01b81526001600160a01b038216600482015260240161023b565b88336001600160a01b0316816001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561032f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103539190611a47565b6001600160a01b0316146103855760405163245aecd360e01b81526001600160a01b038216600482015260240161023b565b6000546040516340c10f1960e01b81526001600160a01b03909116906340c10f19906103b79030908d90600401611a64565b600060405180830381600087803b1580156103d157600080fd5b505af11580156103e5573d6000803e3d6000fd5b5050604051631b8fec7360e11b8152600481018c9052600092506001600160a01b038d16915063371fd8e6906024016020604051808303816000875af1158015610433573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104579190611a7d565b60405163350c35e960e01b81529091506001600160a01b038c169063350c35e9906104889033908d90600401611a64565b600060405180830381600087803b1580156104a257600080fd5b505af11580156104b6573d6000803e3d6000fd5b505050506000871115610860576000886001600160a01b031663d8dfeb456040518163ffffffff1660e01b8152600401602060405180830381865afa158015610503573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105279190611a47565b90506000336001600160a01b03168a6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610573573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105979190611a47565b6001600160a01b031614158061061c5750896001600160a01b0316634665096d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061060a9190611a23565b64ffffffffff168764ffffffffff1614155b90508015610782576040516323b872dd60e01b8152336004820152306024820152604481018990526001600160a01b038316906323b872dd906064016020604051808303816000875af1158015610677573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061069b9190611a96565b50816001600160a01b031663095ea7b38b6001600160a01b031663365a86fc6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156106e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061070d9190611a47565b8a6040518363ffffffff1660e01b815260040161072b929190611a64565b6020604051808303816000875af115801561074a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061076e9190611a96565b5061077b8a898b8a6117ff565b995061085d565b6040516323b872dd60e01b81523360048201526001600160a01b038b81166024830152604482018a90528316906323b872dd906064016020604051808303816000875af11580156107d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107fb9190611a96565b506040516340c10f1960e01b81526001600160a01b038b16906340c10f199061082a9033908d90600401611a64565b600060405180830381600087803b15801561084457600080fd5b505af1158015610858573d6000803e3d6000fd5b505050505b50505b808a11156108e6576000546001600160a01b031663a9059cbb33610884848e611ace565b6040518363ffffffff1660e01b81526004016108a1929190611a64565b6020604051808303816000875af11580156108c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108e49190611a96565b505b60005460405163079cc67960e41b81526001600160a01b03909116906379cc6790906109189033908e90600401611a64565b600060405180830381600087803b15801561093257600080fd5b505af1158015610946573d6000803e3d6000fd5b505050507f8ba6e48d27ab46e18ba0971bb468a2e47a7fac577d846de107eb2fe948c2f5958b8a8c8b8a8c60405161098396959493929190611ae7565b60405180910390a15050505050505050505050565b6000805460405163aa5dd7f160e01b81526001600160a01b03808b1660048301528a9392169063aa5dd7f190602401602060405180830381865afa1580156109e4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a089190611a47565b6001600160a01b031603610a3a57604051631a71b9a760e01b81526001600160a01b038216600482015260240161023b565b6000805460405163aa5dd7f160e01b81526001600160a01b038089166004830152889392169063aa5dd7f190602401602060405180830381865afa158015610a86573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aaa9190611a47565b6001600160a01b031603610adc57604051631a71b9a760e01b81526001600160a01b038216600482015260240161023b565b88336001600160a01b0316816001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b25573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b499190611a47565b6001600160a01b031614610b7b5760405163245aecd360e01b81526001600160a01b038216600482015260240161023b565b60008a6001600160a01b031663d8dfeb456040518163ffffffff1660e01b8152600401602060405180830381865afa158015610bbb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bdf9190611a47565b6000546040516340c10f1960e01b81529192506001600160a01b0316906340c10f1990610c129030908e90600401611a64565b600060405180830381600087803b158015610c2c57600080fd5b505af1158015610c40573d6000803e3d6000fd5b5050604051631b8fec7360e11b8152600481018d9052600092506001600160a01b038e16915063371fd8e6906024016020604051808303816000875af1158015610c8e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cb29190611a7d565b60405163350c35e960e01b81529091506001600160a01b038d169063350c35e990610ce39030908e90600401611a64565b600060405180830381600087803b158015610cfd57600080fd5b505af1158015610d11573d6000803e3d6000fd5b505050506000341115610d7357816001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015610d5957600080fd5b505af1158015610d6d573d6000803e3d6000fd5b50505050505b8715611096576000896001600160a01b031663d8dfeb456040518163ffffffff1660e01b8152600401602060405180830381865afa158015610db9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ddd9190611a47565b90506000336001600160a01b03168b6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e29573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e4d9190611a47565b6001600160a01b0316141580610ed257508a6001600160a01b0316634665096d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e9c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ec09190611a23565b64ffffffffff168864ffffffffff1614155b90508015610fc057816001600160a01b031663095ea7b38c6001600160a01b031663365a86fc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f27573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f4b9190611a47565b8b6040518363ffffffff1660e01b8152600401610f69929190611a64565b6020604051808303816000875af1158015610f88573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fac9190611a96565b50610fb98b8a8c8b6117ff565b9a50611093565b60405163a9059cbb60e01b81526001600160a01b0383169063a9059cbb90610fee908e908d90600401611a64565b6020604051808303816000875af115801561100d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110319190611a96565b506040516340c10f1960e01b81526001600160a01b038c16906340c10f19906110609033908e90600401611a64565b600060405180830381600087803b15801561107a57600080fd5b505af115801561108e573d6000803e3d6000fd5b505050505b50505b808b111561111c576000546001600160a01b031663a9059cbb336110ba848f611ace565b6040518363ffffffff1660e01b81526004016110d7929190611a64565b6020604051808303816000875af11580156110f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061111a9190611a96565b505b60005460405163079cc67960e41b81526001600160a01b03909116906379cc67909061114e9033908f90600401611a64565b600060405180830381600087803b15801561116857600080fd5b505af115801561117c573d6000803e3d6000fd5b50506040516370a0823160e01b8152306004820152600092506001600160a01b03851691506370a0823190602401602060405180830381865afa1580156111c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111eb9190611a7d565b905080156112b857604051632e1a7d4d60e01b8152600481018290526001600160a01b03841690632e1a7d4d90602401600060405180830381600087803b15801561123557600080fd5b505af1158015611249573d6000803e3d6000fd5b50506040516000925033915083908381818185875af1925050503d806000811461128f576040519150601f19603f3d011682016040523d82523d6000602084013e611294565b606091505b50509050806112b657604051633d2cec6f60e21b815260040160405180910390fd5b505b7f8ba6e48d27ab46e18ba0971bb468a2e47a7fac577d846de107eb2fe948c2f5958d8c8e8d8c8e6040516112f196959493929190611ae7565b60405180910390a150505050505050505050505050565b600080600080611319878734611397565b93509350935093506101298785858986868b610998565b6101998282836001600160a01b0316634665096d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611373573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100809190611a23565b600080600080856001600160a01b031663d8dfeb456040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113ff9190611a47565b6001600160a01b0316876001600160a01b031663d8dfeb456040518163ffffffff1660e01b8152600401602060405180830381865afa158015611446573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061146a9190611a47565b6001600160a01b03161461147d57600080fd5b6000876001600160a01b031663ba5d30786040518163ffffffff1660e01b8152600401602060405180830381865afa1580156114bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114e19190611a7d565b90506000886001600160a01b031663e5a4bed36040518163ffffffff1660e01b8152600401602060405180830381865afa158015611523573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115479190611a7d565b90506000818a6001600160a01b031663c54a89ca856040518263ffffffff1660e01b815260040161157a91815260200190565b602060405180830381865afa158015611597573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115bb9190611a7d565b6115c59190611b21565b604051634ef17bcb60e11b8152600481018290529091506000906001600160a01b038b1690639de2f79690602401602060405180830381865afa158015611610573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116349190611a7d565b905060008b6001600160a01b031663d8dfeb456040518163ffffffff1660e01b8152600401602060405180830381865afa158015611676573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061169a9190611a47565b6040516370a0823160e01b81526001600160a01b038e8116600483015291909116906370a0823190602401602060405180830381865afa1580156116e2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117069190611a7d565b905060006117148b83611b21565b905060008c6001600160a01b031663a035b1fe6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611756573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061177a9190611a7d565b905060008160018161179488670de0b6b3a7640000611b34565b61179e9190611b21565b6117a89190611ace565b6117b29190611b4b565b9050828111156117de575081670de0b6b3a76400006117d18383611b34565b6117db9190611b4b565b94505b6117e88789611b21565b9f939e50939c50929a509098505050505050505050565b6000846001600160a01b031663365a86fc6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561183f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118639190611a47565b60405163e29bf42160e01b81523360048201526001600160a01b038781166024830152604482018790526064820186905264ffffffffff85166084830152600060a4830152919091169063e29bf4219060c4016020604051808303816000875af11580156118d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118f99190611a47565b95945050505050565b6001600160a01b038116811461191757600080fd5b50565b64ffffffffff8116811461191757600080fd5b60008060006060848603121561194257600080fd5b833561194d81611902565b9250602084013561195d81611902565b9150604084013561196d8161191a565b809150509250925092565b6000806040838503121561198b57600080fd5b823561199681611902565b915060208301356119a681611902565b809150509250929050565b600080600080600080600060e0888a0312156119cc57600080fd5b87356119d781611902565b9650602088013595506040880135945060608801356119f581611902565b93506080880135925060a0880135915060c0880135611a138161191a565b8091505092959891949750929550565b600060208284031215611a3557600080fd5b8151611a408161191a565b9392505050565b600060208284031215611a5957600080fd5b8151611a4081611902565b6001600160a01b03929092168252602082015260400190565b600060208284031215611a8f57600080fd5b5051919050565b600060208284031215611aa857600080fd5b81518015158114611a4057600080fd5b634e487b7160e01b600052601160045260246000fd5b81810381811115611ae157611ae1611ab8565b92915050565b6001600160a01b0396871681526020810195909552604085019390935293166060830152608082019290925260a081019190915260c00190565b80820180821115611ae157611ae1611ab8565b8082028115828204841417611ae157611ae1611ab8565b600082611b6857634e487b7160e01b600052601260045260246000fd5b50049056fea2646970667358221220b01cc7f8fabff5de6e955c29c8eb0a66f2a1af23a26629d3a49e7a30905a86f864736f6c634300081a0033000000000000000000000000ba3f535bbcccca2a154b573ca6c5a49baae0a3ea","name":"PositionRoller","is_blueprint":false,"license_type":"none","is_fully_verified":false,"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":"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\n/**\n * @notice Interface for wrapped native tokens (e.g., WcBTC, WETH)\n */\ninterface IWrappedNative {\n    function deposit() external payable;\n    function withdraw(uint256) external;\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":"@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":"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 WCBTC() 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/interface/IJuiceDollar.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 IJuiceDollar 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"}],"certified":false,"conflicting_implementations":null,"abi":[{"inputs":[{"internalType":"address","name":"jusd_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"NativeTransferFailed","type":"error"},{"inputs":[{"internalType":"address","name":"pos","type":"address"}],"name":"NotOwner","type":"error"},{"inputs":[{"internalType":"address","name":"pos","type":"address"}],"name":"NotPosition","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"source","type":"address"},{"indexed":false,"internalType":"uint256","name":"collWithdraw","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"repay","type":"uint256"},{"indexed":false,"internalType":"address","name":"target","type":"address"},{"indexed":false,"internalType":"uint256","name":"collDeposit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"mint","type":"uint256"}],"name":"Roll","type":"event"},{"inputs":[{"internalType":"contract IPosition","name":"source","type":"address"},{"internalType":"uint256","name":"repay","type":"uint256"},{"internalType":"uint256","name":"collWithdraw","type":"uint256"},{"internalType":"contract IPosition","name":"target","type":"address"},{"internalType":"uint256","name":"mint","type":"uint256"},{"internalType":"uint256","name":"collDeposit","type":"uint256"},{"internalType":"uint40","name":"expiration","type":"uint40"}],"name":"roll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IPosition","name":"source","type":"address"},{"internalType":"contract IPosition","name":"target","type":"address"}],"name":"rollFully","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IPosition","name":"source","type":"address"},{"internalType":"contract IPosition","name":"target","type":"address"}],"name":"rollFullyNative","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IPosition","name":"source","type":"address"},{"internalType":"contract IPosition","name":"target","type":"address"},{"internalType":"uint40","name":"expiration","type":"uint40"}],"name":"rollFullyNativeWithExpiration","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IPosition","name":"source","type":"address"},{"internalType":"contract IPosition","name":"target","type":"address"},{"internalType":"uint40","name":"expiration","type":"uint40"}],"name":"rollFullyWithExpiration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IPosition","name":"source","type":"address"},{"internalType":"uint256","name":"repay","type":"uint256"},{"internalType":"uint256","name":"collWithdraw","type":"uint256"},{"internalType":"contract IPosition","name":"target","type":"address"},{"internalType":"uint256","name":"mint","type":"uint256"},{"internalType":"uint256","name":"collDeposit","type":"uint256"},{"internalType":"uint40","name":"expiration","type":"uint40"}],"name":"rollNative","outputs":[],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}],"is_changed_bytecode":false,"is_partially_verified":true,"constructor_args":"0x000000000000000000000000ba3f535bbcccca2a154b573ca6c5a49baae0a3ea"}