{"file_path":"contracts/MintingHubV2/PositionRoller.sol","creation_status":"success","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport '../interface/IERC20.sol';\nimport '../interface/IFrankencoin.sol';\nimport '../utils/Ownable.sol';\nimport '../interface/IReserve.sol';\n\nimport './interfaceV2/IPosition.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\tIFrankencoin private zchf;\n\n\terror NotOwner(address pos);\n\terror NotPosition(address pos);\n\terror Log(uint256, uint256, uint256);\n\n\tevent Roll(address source, uint256 collWithdraw, uint256 repay, address target, uint256 collDeposit, uint256 mint);\n\n\tconstructor(address zchf_) {\n\t\tzchf = IFrankencoin(zchf_);\n\t}\n\n\t/**\n\t * Convenience method to roll and old position into a new one.\n\t *\n\t * Pre-condition is an allowance for the roller to spend the collateral assset on behalf of the caller,\n\t * i.e. one should set collateral.approve(roller, collateral.balanceOf(sourcePosition));\n\t *\n\t * The following is assumed:\n\t * - If the limit of the target position permits, the user wants to roll everything\n\t * - The user does not want to add additional collateral, but excess collateral is returned\n\t * - If not enough can be minted in the new position, it is ok for the roller to use ZCHF from the msg.sender\n\t */\n\tfunction rollFully(IPosition source, IPosition target) external {\n\t\trollFullyWithExpiration(source, target, target.expiration());\n\t}\n\n\t/**\n\t * Like rollFully, but with a custom expiration date for the new position.\n\t */\n\tfunction rollFullyWithExpiration(IPosition source, IPosition target, uint40 expiration) public {\n\t\trequire(source.collateral() == target.collateral());\n\t\tuint256 repay = findRepaymentAmount(source);\n\t\tuint256 mintAmount = target.getMintAmount(repay);\n\t\tuint256 collateralToWithdraw = IERC20(source.collateral()).balanceOf(address(source));\n\t\tuint256 targetPrice = target.price();\n\t\tuint256 depositAmount = (mintAmount * 10 ** 18 + targetPrice - 1) / targetPrice; // round up\n\t\tif (depositAmount > collateralToWithdraw) {\n\t\t\t// If we need more collateral than available from the old position, we opt for taking\n\t\t\t// the missing funds from the caller instead of taking additional collateral from the caller\n\t\t\tdepositAmount = collateralToWithdraw;\n\t\t\tmintAmount = (depositAmount * target.price()) / 10 ** 18; // round down, rest will be taken from caller\n\t\t}\n\t\troll(source, repay, collateralToWithdraw, target, mintAmount, depositAmount, expiration);\n\t}\n\n\t/**\n\t * Doing a binary search is not very efficient, but guaranteed to return a valid result without rounding errors.\n\t * To save gas costs, the frontend can also call this and other methods to calculate the right parameters and\n\t * then call 'roll' directly.\n\t */\n\tfunction findRepaymentAmount(IPosition pos) public view returns (uint256) {\n\t\tuint256 minted = pos.minted();\n\t\tuint24 reservePPM = pos.reserveContribution();\n\t\tif (minted == 0) {\n\t\t\treturn 0;\n\t\t}\n\t\tuint256 higherResult = zchf.calculateFreedAmount(minted, reservePPM);\n\t\tif (higherResult == minted) {\n\t\t\treturn minted;\n\t\t}\n\t\treturn binarySearch(minted, reservePPM, 0, 0, minted, higherResult);\n\t}\n\n\t// max call stack depth is 1024 in solidity. Binary search on 256 bit number takes at most 256 steps, so it should be fine.\n\tfunction binarySearch(\n\t\tuint256 target,\n\t\tuint24 reservePPM,\n\t\tuint256 lowerBound,\n\t\tuint256 lowerResult,\n\t\tuint256 higherBound,\n\t\tuint256 higherResult\n\t) internal view returns (uint256) {\n\t\tuint256 middle = (lowerBound + higherBound) / 2;\n\t\tif (middle == lowerBound) {\n\t\t\treturn higherBound; // we have reached max precision without exact match, return next higher result to be on the safe side\n\t\t} else {\n\t\t\tuint256 middleResult = zchf.calculateFreedAmount(middle, reservePPM);\n\t\t\tif (middleResult == target) {\n\t\t\t\treturn middle;\n\t\t\t} else if (middleResult < target) {\n\t\t\t\treturn binarySearch(target, reservePPM, middle, middleResult, higherBound, higherResult);\n\t\t\t} else {\n\t\t\t\treturn binarySearch(target, reservePPM, lowerBound, lowerResult, middle, middleResult);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Rolls the source position into the target position using a flash loan.\n\t * Both the source and the target position must recognize this roller.\n\t * It is the responsibility of the caller to ensure that both positions are valid contracts.\n\t *\n\t * @param source The source position, must be owned by the msg.sender .\n\t * @param repay The amount to flash loan in order to repay the source position and free up some or all collateral.\n\t * @param collWithdraw Collateral to move from the source position to the msg.sender .\n\t * @param target The target position. If not owned by msg.sender or if it does not have the desired expiration,\n\t *               it is cloned to create a position owned by the msg.sender.\n\t * @param mint The amount to be minted from the target position using collateral from msg.sender.\n\t * @param collDeposit The amount of collateral to be send from msg.sender to the target position.\n\t * @param expiration The desired expiration date for the target position.\n\t */\n\tfunction roll(\n\t\tIPosition source,\n\t\tuint256 repay,\n\t\tuint256 collWithdraw,\n\t\tIPosition target,\n\t\tuint256 mint,\n\t\tuint256 collDeposit,\n\t\tuint40 expiration\n\t) public valid(source) valid(target) own(source) {\n\t\tzchf.mint(address(this), repay); // take a flash loan\n\t\tsource.repay(repay);\n\t\tsource.withdrawCollateral(msg.sender, collWithdraw);\n\t\tif (mint > 0) {\n\t\t\tIERC20 targetCollateral = IERC20(target.collateral());\n\t\t\tif (Ownable(address(target)).owner() != msg.sender || expiration != target.expiration()) {\n\t\t\t\ttargetCollateral.transferFrom(msg.sender, address(this), collDeposit); // get the new collateral\n\t\t\t\ttargetCollateral.approve(target.hub(), collDeposit); // approve the new collateral and clone:\n\t\t\t\ttarget = IPosition(IMintingHub(target.hub()).clone(msg.sender, address(target), collDeposit, mint, expiration));\n\t\t\t} else {\n\t\t\t\t// We can roll into the provided existing position\n\t\t\t\t// We do not verify whether the target position has been created by the known minting hub in order\n\t\t\t\t// to allow positions to be rolled into future versions of the minting hub\n\t\t\t\ttargetCollateral.transferFrom(msg.sender, address(target), collDeposit);\n\t\t\t\ttarget.mint(msg.sender, mint);\n\t\t\t}\n\t\t}\n\t\tzchf.burnFrom(msg.sender, repay); // repay the flash loan\n\t\temit Roll(address(source), collWithdraw, repay, address(target), collDeposit, mint);\n\t}\n\n\tmodifier own(IPosition pos) {\n\t\tif (Ownable(address(pos)).owner() != msg.sender) revert NotOwner(address(pos));\n\t\t_;\n\t}\n\n\tmodifier valid(IPosition pos) {\n\t\tif (zchf.getPositionParent(address(pos)) == address(0x0)) revert NotPosition(address(pos));\n\t\t_;\n\t}\n}\n\ninterface IMintingHub {\n\tfunction clone(\n\t\taddress owner,\n\t\taddress parent,\n\t\tuint256 _initialCollateral,\n\t\tuint256 _initialMint,\n\t\tuint40 expiration\n\t) external returns (address);\n}\n","deployed_bytecode":"0x608060405234801561001057600080fd5b506004361061004c5760003560e01c8063566dfba8146100515780635e871b541461007657806389523c331461008b578063c2a1c5061461009e575b600080fd5b61006461005f366004610f91565b6100b1565b60405190815260200160405180910390f35b610089610084366004610fc8565b610233565b005b610089610099366004611013565b6105a5565b6100896100ac366004611085565b610e22565b600080826001600160a01b0316634f02c4206040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100f2573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061011691906110be565b90506000836001600160a01b0316633a7c29fb6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610158573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061017c91906110d7565b905081600003610190575060009392505050565b60008054604051633824f22960e21b81526004810185905262ffffff841660248201526001600160a01b039091169063e093c8a490604401602060405180830381865afa1580156101e5573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061020991906110be565b905082810361021b5750909392505050565b61022a83836000808786610e8d565b95945050505050565b816001600160a01b031663d8dfeb456040518163ffffffff1660e01b8152600401602060405180830381865afa158015610271573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061029591906110fc565b6001600160a01b0316836001600160a01b031663d8dfeb456040518163ffffffff1660e01b8152600401602060405180830381865afa1580156102dc573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061030091906110fc565b6001600160a01b03161461031357600080fd5b600061031e846100b1565b604051634ef17bcb60e11b8152600481018290529091506000906001600160a01b03851690639de2f79690602401602060405180830381865afa158015610369573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061038d91906110be565b90506000856001600160a01b031663d8dfeb456040518163ffffffff1660e01b8152600401602060405180830381865afa1580156103cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103f391906110fc565b6040516370a0823160e01b81526001600160a01b03888116600483015291909116906370a0823190602401602060405180830381865afa15801561043b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061045f91906110be565b90506000856001600160a01b031663a035b1fe6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156104a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104c591906110be565b90506000816001816104df87670de0b6b3a764000061112f565b6104e9919061114c565b6104f3919061115f565b6104fd9190611172565b90508281111561058c57829050670de0b6b3a7640000876001600160a01b031663a035b1fe6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610551573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061057591906110be565b61057f908361112f565b6105899190611172565b93505b61059b8886858a88868c6105a5565b5050505050505050565b6000805460405163aa5dd7f160e01b81526001600160a01b03808b1660048301528a9392169063aa5dd7f190602401602060405180830381865afa1580156105f1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061061591906110fc565b6001600160a01b03160361064c57604051631a71b9a760e01b81526001600160a01b03821660048201526024015b60405180910390fd5b6000805460405163aa5dd7f160e01b81526001600160a01b038089166004830152889392169063aa5dd7f190602401602060405180830381865afa158015610698573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106bc91906110fc565b6001600160a01b0316036106ee57604051631a71b9a760e01b81526001600160a01b0382166004820152602401610643565b88336001600160a01b0316816001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610737573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061075b91906110fc565b6001600160a01b03161461078d5760405163245aecd360e01b81526001600160a01b0382166004820152602401610643565b6000546040516340c10f1960e01b8152306004820152602481018b90526001600160a01b03909116906340c10f1990604401600060405180830381600087803b1580156107d957600080fd5b505af11580156107ed573d6000803e3d6000fd5b5050604051631b8fec7360e11b8152600481018c90526001600160a01b038d16925063371fd8e691506024016020604051808303816000875af1158015610838573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061085c91906110be565b5060405163350c35e960e01b8152336004820152602481018990526001600160a01b038b169063350c35e990604401600060405180830381600087803b1580156108a557600080fd5b505af11580156108b9573d6000803e3d6000fd5b505050506000861115610d52576000876001600160a01b031663d8dfeb456040518163ffffffff1660e01b8152600401602060405180830381865afa158015610906573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061092a91906110fc565b9050336001600160a01b0316886001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610974573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061099891906110fc565b6001600160a01b0316141580610a1d5750876001600160a01b0316634665096d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109e7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a0b9190611194565b64ffffffffff168564ffffffffff1614155b15610c75576040516323b872dd60e01b8152336004820152306024820152604481018790526001600160a01b038216906323b872dd906064016020604051808303816000875af1158015610a75573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a9991906111b1565b50806001600160a01b031663095ea7b3896001600160a01b031663365a86fc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ae7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b0b91906110fc565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602481018990526044016020604051808303816000875af1158015610b58573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b7c91906111b1565b50876001600160a01b031663365a86fc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610bbb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bdf91906110fc565b604051634ec7f95360e11b81523360048201526001600160a01b038a8116602483015260448201899052606482018a905264ffffffffff881660848301529190911690639d8ff2a69060a4016020604051808303816000875af1158015610c4a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c6e91906110fc565b9750610d50565b6040516323b872dd60e01b81523360048201526001600160a01b038981166024830152604482018890528216906323b872dd906064016020604051808303816000875af1158015610cca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cee91906111b1565b506040516340c10f1960e01b8152336004820152602481018890526001600160a01b038916906340c10f1990604401600060405180830381600087803b158015610d3757600080fd5b505af1158015610d4b573d6000803e3d6000fd5b505050505b505b60005460405163079cc67960e41b8152336004820152602481018b90526001600160a01b03909116906379cc679090604401600060405180830381600087803b158015610d9e57600080fd5b505af1158015610db2573d6000803e3d6000fd5b5050604080516001600160a01b038e81168252602082018d90528183018e90528b1660608201526080810189905260a081018a905290517f8ba6e48d27ab46e18ba0971bb468a2e47a7fac577d846de107eb2fe948c2f59593509081900360c0019150a150505050505050505050565b610e898282836001600160a01b0316634665096d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e65573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100849190611194565b5050565b6000806002610e9c858861114c565b610ea69190611172565b9050858103610eb85783915050610f6f565b60008054604051633824f22960e21b81526004810184905262ffffff8a1660248201526001600160a01b039091169063e093c8a490604401602060405180830381865afa158015610f0d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f3191906110be565b9050888103610f4257509050610f6f565b88811015610f6157610f58898984848989610e8d565b92505050610f6f565b610f58898989898686610e8d565b9695505050505050565b6001600160a01b0381168114610f8e57600080fd5b50565b600060208284031215610fa357600080fd5b8135610fae81610f79565b9392505050565b64ffffffffff81168114610f8e57600080fd5b600080600060608486031215610fdd57600080fd5b8335610fe881610f79565b92506020840135610ff881610f79565b9150604084013561100881610fb5565b809150509250925092565b600080600080600080600060e0888a03121561102e57600080fd5b873561103981610f79565b96506020880135955060408801359450606088013561105781610f79565b93506080880135925060a0880135915060c088013561107581610fb5565b8091505092959891949750929550565b6000806040838503121561109857600080fd5b82356110a381610f79565b915060208301356110b381610f79565b809150509250929050565b6000602082840312156110d057600080fd5b5051919050565b6000602082840312156110e957600080fd5b815162ffffff81168114610fae57600080fd5b60006020828403121561110e57600080fd5b8151610fae81610f79565b634e487b7160e01b600052601160045260246000fd5b808202811582820484141761114657611146611119565b92915050565b8082018082111561114657611146611119565b8181038181111561114657611146611119565b60008261118f57634e487b7160e01b600052601260045260246000fd5b500490565b6000602082840312156111a657600080fd5b8151610fae81610fb5565b6000602082840312156111c357600080fd5b81518015158114610fae57600080fdfea26469706673582212205c50844207f69aab9914ed222a0a989f00a18dad8d719460271fa93b3420873c64736f6c63430008140033","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},"remappings":[]},"optimization_runs":200,"sourcify_repo_url":"https://repo.sourcify.dev/contracts/full_match/1/0xAD0107D3Da540Fd54b1931735b65110C909ea6B6/","decoded_constructor_args":[["0xB58E61C3098d85632Df34EecfB899A1Ed80921cB",{"internalType":"address","name":"zchf_","type":"address"}]],"compiler_version":"0.8.20+commit.a1b79de6","is_verified_via_verifier_alliance":false,"verified_at":"2024-11-28T14:52:01.998246Z","implementations":[],"proxy_type":null,"external_libraries":[],"creation_bytecode":"0x608060405234801561001057600080fd5b5060405161129c38038061129c83398101604081905261002f91610054565b600080546001600160a01b0319166001600160a01b0392909216919091179055610084565b60006020828403121561006657600080fd5b81516001600160a01b038116811461007d57600080fd5b9392505050565b611209806100936000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c8063566dfba8146100515780635e871b541461007657806389523c331461008b578063c2a1c5061461009e575b600080fd5b61006461005f366004610f91565b6100b1565b60405190815260200160405180910390f35b610089610084366004610fc8565b610233565b005b610089610099366004611013565b6105a5565b6100896100ac366004611085565b610e22565b600080826001600160a01b0316634f02c4206040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100f2573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061011691906110be565b90506000836001600160a01b0316633a7c29fb6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610158573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061017c91906110d7565b905081600003610190575060009392505050565b60008054604051633824f22960e21b81526004810185905262ffffff841660248201526001600160a01b039091169063e093c8a490604401602060405180830381865afa1580156101e5573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061020991906110be565b905082810361021b5750909392505050565b61022a83836000808786610e8d565b95945050505050565b816001600160a01b031663d8dfeb456040518163ffffffff1660e01b8152600401602060405180830381865afa158015610271573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061029591906110fc565b6001600160a01b0316836001600160a01b031663d8dfeb456040518163ffffffff1660e01b8152600401602060405180830381865afa1580156102dc573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061030091906110fc565b6001600160a01b03161461031357600080fd5b600061031e846100b1565b604051634ef17bcb60e11b8152600481018290529091506000906001600160a01b03851690639de2f79690602401602060405180830381865afa158015610369573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061038d91906110be565b90506000856001600160a01b031663d8dfeb456040518163ffffffff1660e01b8152600401602060405180830381865afa1580156103cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103f391906110fc565b6040516370a0823160e01b81526001600160a01b03888116600483015291909116906370a0823190602401602060405180830381865afa15801561043b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061045f91906110be565b90506000856001600160a01b031663a035b1fe6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156104a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104c591906110be565b90506000816001816104df87670de0b6b3a764000061112f565b6104e9919061114c565b6104f3919061115f565b6104fd9190611172565b90508281111561058c57829050670de0b6b3a7640000876001600160a01b031663a035b1fe6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610551573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061057591906110be565b61057f908361112f565b6105899190611172565b93505b61059b8886858a88868c6105a5565b5050505050505050565b6000805460405163aa5dd7f160e01b81526001600160a01b03808b1660048301528a9392169063aa5dd7f190602401602060405180830381865afa1580156105f1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061061591906110fc565b6001600160a01b03160361064c57604051631a71b9a760e01b81526001600160a01b03821660048201526024015b60405180910390fd5b6000805460405163aa5dd7f160e01b81526001600160a01b038089166004830152889392169063aa5dd7f190602401602060405180830381865afa158015610698573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106bc91906110fc565b6001600160a01b0316036106ee57604051631a71b9a760e01b81526001600160a01b0382166004820152602401610643565b88336001600160a01b0316816001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610737573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061075b91906110fc565b6001600160a01b03161461078d5760405163245aecd360e01b81526001600160a01b0382166004820152602401610643565b6000546040516340c10f1960e01b8152306004820152602481018b90526001600160a01b03909116906340c10f1990604401600060405180830381600087803b1580156107d957600080fd5b505af11580156107ed573d6000803e3d6000fd5b5050604051631b8fec7360e11b8152600481018c90526001600160a01b038d16925063371fd8e691506024016020604051808303816000875af1158015610838573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061085c91906110be565b5060405163350c35e960e01b8152336004820152602481018990526001600160a01b038b169063350c35e990604401600060405180830381600087803b1580156108a557600080fd5b505af11580156108b9573d6000803e3d6000fd5b505050506000861115610d52576000876001600160a01b031663d8dfeb456040518163ffffffff1660e01b8152600401602060405180830381865afa158015610906573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061092a91906110fc565b9050336001600160a01b0316886001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610974573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061099891906110fc565b6001600160a01b0316141580610a1d5750876001600160a01b0316634665096d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109e7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a0b9190611194565b64ffffffffff168564ffffffffff1614155b15610c75576040516323b872dd60e01b8152336004820152306024820152604481018790526001600160a01b038216906323b872dd906064016020604051808303816000875af1158015610a75573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a9991906111b1565b50806001600160a01b031663095ea7b3896001600160a01b031663365a86fc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ae7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b0b91906110fc565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602481018990526044016020604051808303816000875af1158015610b58573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b7c91906111b1565b50876001600160a01b031663365a86fc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610bbb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bdf91906110fc565b604051634ec7f95360e11b81523360048201526001600160a01b038a8116602483015260448201899052606482018a905264ffffffffff881660848301529190911690639d8ff2a69060a4016020604051808303816000875af1158015610c4a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c6e91906110fc565b9750610d50565b6040516323b872dd60e01b81523360048201526001600160a01b038981166024830152604482018890528216906323b872dd906064016020604051808303816000875af1158015610cca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cee91906111b1565b506040516340c10f1960e01b8152336004820152602481018890526001600160a01b038916906340c10f1990604401600060405180830381600087803b158015610d3757600080fd5b505af1158015610d4b573d6000803e3d6000fd5b505050505b505b60005460405163079cc67960e41b8152336004820152602481018b90526001600160a01b03909116906379cc679090604401600060405180830381600087803b158015610d9e57600080fd5b505af1158015610db2573d6000803e3d6000fd5b5050604080516001600160a01b038e81168252602082018d90528183018e90528b1660608201526080810189905260a081018a905290517f8ba6e48d27ab46e18ba0971bb468a2e47a7fac577d846de107eb2fe948c2f59593509081900360c0019150a150505050505050505050565b610e898282836001600160a01b0316634665096d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e65573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100849190611194565b5050565b6000806002610e9c858861114c565b610ea69190611172565b9050858103610eb85783915050610f6f565b60008054604051633824f22960e21b81526004810184905262ffffff8a1660248201526001600160a01b039091169063e093c8a490604401602060405180830381865afa158015610f0d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f3191906110be565b9050888103610f4257509050610f6f565b88811015610f6157610f58898984848989610e8d565b92505050610f6f565b610f58898989898686610e8d565b9695505050505050565b6001600160a01b0381168114610f8e57600080fd5b50565b600060208284031215610fa357600080fd5b8135610fae81610f79565b9392505050565b64ffffffffff81168114610f8e57600080fd5b600080600060608486031215610fdd57600080fd5b8335610fe881610f79565b92506020840135610ff881610f79565b9150604084013561100881610fb5565b809150509250925092565b600080600080600080600060e0888a03121561102e57600080fd5b873561103981610f79565b96506020880135955060408801359450606088013561105781610f79565b93506080880135925060a0880135915060c088013561107581610fb5565b8091505092959891949750929550565b6000806040838503121561109857600080fd5b82356110a381610f79565b915060208301356110b381610f79565b809150509250929050565b6000602082840312156110d057600080fd5b5051919050565b6000602082840312156110e957600080fd5b815162ffffff81168114610fae57600080fd5b60006020828403121561110e57600080fd5b8151610fae81610f79565b634e487b7160e01b600052601160045260246000fd5b808202811582820484141761114657611146611119565b92915050565b8082018082111561114657611146611119565b8181038181111561114657611146611119565b60008261118f57634e487b7160e01b600052601260045260246000fd5b500490565b6000602082840312156111a657600080fd5b8151610fae81610fb5565b6000602082840312156111c357600080fd5b81518015158114610fae57600080fdfea26469706673582212205c50844207f69aab9914ed222a0a989f00a18dad8d719460271fa93b3420873c64736f6c63430008140033000000000000000000000000b58e61c3098d85632df34eecfb899a1ed80921cb","name":"PositionRoller","is_blueprint":false,"license_type":"none","is_fully_verified":true,"is_verified_via_eth_bytecode_db":true,"language":"solidity","evm_version":"paris","can_be_visualized_via_sol2uml":true,"is_verified_via_sourcify":true,"additional_sources":[{"file_path":"contracts/MintingHubV2/interfaceV2/IPosition.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport '../../interface/IERC20.sol';\n\ninterface IPosition {\n\tfunction hub() external view returns (address);\n\n\tfunction collateral() external view returns (IERC20);\n\n\tfunction minimumCollateral() external view returns (uint256);\n\n\tfunction price() external view returns (uint256);\n\n\tfunction minted() external view returns (uint256);\n\n\tfunction challengedAmount() external view returns (uint256);\n\n\tfunction original() external view returns (address);\n\n\tfunction expiration() external view returns (uint40);\n\n\tfunction cooldown() external view returns (uint40);\n\n\tfunction limit() external view returns (uint256);\n\n\tfunction challengePeriod() external view returns (uint40);\n\n\tfunction start() external view returns (uint40);\n\n\tfunction riskPremiumPPM() external view returns (uint24);\n\n\tfunction reserveContribution() external view returns (uint24);\n\n\tfunction initialize(address parent, uint40 _expiration) external;\n\n\tfunction assertCloneable() external;\n\n\tfunction notifyMint(uint256 mint_) external;\n\n\tfunction notifyRepaid(uint256 repaid_) external;\n\n\tfunction availableForClones() external view returns (uint256);\n\n\tfunction availableForMinting() external view returns (uint256);\n\n\tfunction deny(address[] calldata helpers, string calldata message) external;\n\n\tfunction getUsableMint(uint256 totalMint, bool afterFees) external view returns (uint256);\n\n\tfunction getMintAmount(uint256 usableMint) external view returns (uint256);\n\n\tfunction adjust(uint256 newMinted, uint256 newCollateral, uint256 newPrice) external;\n\n\tfunction adjustPrice(uint256 newPrice) external;\n\n\tfunction mint(address target, uint256 amount) external;\n\n\tfunction calculateCurrentFee() external view returns (uint24);\n\n\tfunction annualInterestPPM() external view returns (uint24);\n\n\tfunction calculateFee(uint256 exp) external view returns (uint24);\n\n\tfunction repay(uint256 amount) external returns (uint256);\n\n\tfunction forceSale(address buyer, uint256 collAmount, uint256 proceeds) external;\n\n\tfunction withdraw(address token, address target, uint256 amount) external;\n\n\tfunction withdrawCollateral(address target, uint256 amount) external;\n\n\tfunction challengeData() external view returns (uint256 liqPrice, uint40 phase);\n\n\tfunction notifyChallengeStarted(uint256 size) external;\n\n\tfunction notifyChallengeAverted(uint256 size) external;\n\n\tfunction notifyChallengeSucceeded(address _bidder, uint256 _size) external returns (address, uint256, uint256, uint32);\n}\n"},{"file_path":"contracts/interface/IERC20.sol","source_code":"/**\n * SPDX-License-Identifier: MIT\n *\n * Copyright (c) 2016-2019 zOS Global Limited\n *\n */\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP. Does not include\n * the optional functions; to access them see `ERC20Detailed`.\n */\n\ninterface IERC20 {\n    function name() external view returns (string memory);\n\n    function symbol() external view returns (string memory);\n\n    function decimals() external view returns (uint8);\n\n    /**\n     * @dev Returns the amount of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the amount of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves `amount` tokens from the caller's account to `recipient`.\n     *\n     * Returns always true. Throws error on failure.\n     *\n     * Emits a `Transfer` event.\n     */\n    function transfer(address recipient, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through `transferFrom`. This is\n     * zero by default.\n     *\n     * This value can change when `approve` or `transferFrom` are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * > Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an `Approval` event.\n     */\n    function approve(address spender, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Moves `amount` tokens from `sender` to `recipient` using the\n     * allowance mechanism. `amount` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns always true. Throws error on failure.\n     *\n     * Emits a `Transfer` event.\n     */\n    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to `approve`. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n"},{"file_path":"contracts/interface/IFrankencoin.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./IReserve.sol\";\n\ninterface IFrankencoin is IERC20 {\n    function suggestMinter(address _minter, uint256 _applicationPeriod, uint256 _applicationFee, string calldata _message) 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, uint32 feePPM) external;\n\n    function burnFrom(address target, uint256 amount) external;\n\n    function burnWithoutReserve(uint256 amountIncludingReserve, uint32 reservePPM) external;\n\n    function burnFromWithReserve(address payer, uint256 targetTotalBurnAmount, uint32 _reservePPM) external returns (uint256);\n\n    function burnWithReserve(uint256 amountExcludingReserve, uint32 reservePPM) external returns (uint256);\n\n    function coverLoss(address source, uint256 amount) external;\n\n    function collectProfits(address source, uint256 _amount) external;\n}\n"},{"file_path":"contracts/interface/IReserve.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./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}"},{"file_path":"contracts/utils/Ownable.sol","source_code":"// SPDX-License-Identifier: MIT\n//\n// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol\n//\n// Modifications:\n// - Replaced Context._msgSender() with msg.sender\n// - Made leaner\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n */\ncontract Ownable {\n\n    address public owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    error NotOwner();\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 onlyOwner {\n        _setOwner(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 _setOwner(address newOwner) internal {\n        require(newOwner != address(0x0)); // ensure initialization can only done once\n        address oldOwner = owner;\n        owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n\n    function _requireOwner(address sender) internal view {\n        if (owner != sender && owner != address(0x0)) revert NotOwner();\n    }\n\n    modifier onlyOwner() {\n        _requireOwner(msg.sender);\n        _;\n    }\n}\n"}],"certified":false,"conflicting_implementations":null,"abi":[{"inputs":[{"internalType":"address","name":"zchf_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"Log","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":"pos","type":"address"}],"name":"findRepaymentAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","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":"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"},{"internalType":"uint40","name":"expiration","type":"uint40"}],"name":"rollFullyWithExpiration","outputs":[],"stateMutability":"nonpayable","type":"function"}],"is_changed_bytecode":false,"is_partially_verified":false,"constructor_args":"0x000000000000000000000000b58e61c3098d85632df34eecfb899a1ed80921cb"}