{"file_path":"contracts/MintingHubV2/PositionFactory.sol","creation_status":"success","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {Position} from \"./Position.sol\";\nimport {IDecentralizedEURO} from \"../interface/IDecentralizedEURO.sol\";\n\ncontract PositionFactory {\n    /**\n     * Create a completely new position in a newly deployed contract.\n     * Must be called through the minting hub to be recognized as a valid position.\n     */\n    function createNewPosition(\n        address _owner,\n        address _deuro,\n        address _collateral,\n        uint256 _minCollateral,\n        uint256 _initialLimit,\n        uint40 _initPeriod,\n        uint40 _duration,\n        uint40 _challengePeriod,\n        uint24 _riskPremiumPPM,\n        uint256 _liqPrice,\n        uint24 _reserve\n    ) external returns (address) {\n        return\n            address(\n                new Position(\n                    _owner,\n                    msg.sender,\n                    _deuro,\n                    _collateral,\n                    _minCollateral,\n                    _initialLimit,\n                    _initPeriod,\n                    _duration,\n                    _challengePeriod,\n                    _riskPremiumPPM,\n                    _liqPrice,\n                    _reserve\n                )\n            );\n    }\n\n    /**\n     * @notice Clone an existing position. This can be a clone of another clone,\n     * or an original position.\n     * @param _parent address of the position we want to clone\n     * @return address of the newly created clone position\n     */\n    function clonePosition(address _parent) external returns (address) {\n        Position parent = Position(_parent);\n        parent.assertCloneable();\n        Position clone = Position(_createClone(parent.original()));\n        return address(clone);\n    }\n\n    // github.com/optionality/clone-factory/blob/32782f82dfc5a00d103a7e61a17a5dedbd1e8e9d/contracts/CloneFactory.sol\n    function _createClone(address target) internal returns (address result) {\n        bytes20 targetBytes = bytes20(target);\n        assembly {\n            let clone := mload(0x40)\n            mstore(clone, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)\n            mstore(add(clone, 0x14), targetBytes)\n            mstore(add(clone, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)\n            result := create(0, clone, 0x37)\n        }\n        require(result != address(0), \"ERC1167: create failed\");\n    }\n}","deployed_bytecode":"0x608060405234801561001057600080fd5b50600436106100365760003560e01c80635d824f761461003b578063b3e891801461006a575b600080fd5b61004e61004936600461029e565b61007d565b6040516001600160a01b03909116815260200160405180910390f35b61004e61007836600461035b565b6100d9565b60008b338c8c8c8c8c8c8c8c8c8c6040516100979061024c565b6100ac9c9b9a9998979695949392919061037f565b604051809103906000f0801580156100c8573d6000803e3d6000fd5b509c9b505050505050505050505050565b600080829050806001600160a01b0316630e49d77e6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561011a57600080fd5b505af115801561012e573d6000803e3d6000fd5b50505050600061019e826001600160a01b03166346c715fa6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610175573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610199919061040f565b6101a6565b949350505050565b6000808260601b9050604051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b81528160148201526e5af43d82803e903d91602b57fd5bf360881b60288201526037816000f09250506001600160a01b0382166102465760405162461bcd60e51b8152602060048201526016602482015275115490cc4c4d8dce8818dc99585d194819985a5b195960521b604482015260640160405180910390fd5b50919050565b613a598061042d83390190565b6001600160a01b038116811461026e57600080fd5b50565b803564ffffffffff8116811461028657600080fd5b919050565b803562ffffff8116811461028657600080fd5b60008060008060008060008060008060006101608c8e0312156102c057600080fd5b8b356102cb81610259565b9a5060208c01356102db81610259565b995060408c01356102eb81610259565b985060608c0135975060808c0135965061030760a08d01610271565b955061031560c08d01610271565b945061032360e08d01610271565b93506103326101008d0161028b565b92506101208c013591506103496101408d0161028b565b90509295989b509295989b9093969950565b60006020828403121561036d57600080fd5b813561037881610259565b9392505050565b6001600160a01b038d811682528c811660208301528b811660408301528a1660608201526080810189905260a0810188905264ffffffffff87811660c0830152861660e0820152610180810164ffffffffff861661010083015262ffffff8516610120830152836101408301526103fe61016083018462ffffff169052565b9d9c50505050505050505050505050565b60006020828403121561042157600080fd5b81516103788161025956fe6101c060405234801561001157600080fd5b50604051613a59380380613a59833981016040819052610030916103d8565b8b6001600160a01b03811661006057604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b6100698161012f565b503060e0526001600160a01b038b8116610100528a81166101205289166101405262ffffff8084166101805281166101a05261016088905264ffffffffff841660a0526100b686426104c2565b64ffffffffff1660c08190526005805464ffffffffff1916821790556100dd9086906104c2565b6005805464ffffffffff92909216650100000000000264ffffffffff60281b199092169190911790556080879052610115828861017f565b61011e8361022e565b505050505050505050505050610591565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000610189610320565b905060c05164ffffffffff1642101580156101b057506001546101ad9060026104e5565b83115b156101e7578260015460026101c591906104e5565b6040516387ebe85d60e01b815260048101929092526024820152604401610057565b6101f9670de0b6b3a7640000836104e5565b61020382856104e5565b111561022757828161021d670de0b6b3a7640000856104e5565b6101c591906104fc565b5050600155565b80610100516001600160a01b031663664e97046040518163ffffffff1660e01b8152600401602060405180830381865afa158015610270573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610294919061051e565b6001600160a01b03166306a7b3766040518163ffffffff1660e01b8152600401602060405180830381865afa1580156102d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102f59190610542565b6102ff919061055d565b6005600b6101000a81548162ffffff021916908362ffffff16021790555050565b610140516040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa15801561036a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061038e9190610578565b905090565b6001600160a01b03811681146103a857600080fd5b50565b805164ffffffffff811681146103c057600080fd5b919050565b805162ffffff811681146103c057600080fd5b6000806000806000806000806000806000806101808d8f0312156103fb57600080fd5b8c5161040681610393565b60208e0151909c5061041781610393565b60408e0151909b5061042881610393565b60608e0151909a5061043981610393565b60808e015160a08f0151919a509850965061045660c08e016103ab565b955061046460e08e016103ab565b94506104736101008e016103ab565b93506104826101208e016103c5565b6101408e0151909350915061049a6101608e016103c5565b90509295989b509295989b509295989b565b634e487b7160e01b600052601160045260246000fd5b64ffffffffff81811683821601908111156104df576104df6104ac565b92915050565b80820281158282048414176104df576104df6104ac565b60008261051957634e487b7160e01b600052601260045260246000fd5b500490565b60006020828403121561053057600080fd5b815161053b81610393565b9392505050565b60006020828403121561055457600080fd5b61053b826103c5565b62ffffff81811683821601908111156104df576104df6104ac565b60006020828403121561058a57600080fd5b5051919050565b60805160a05160c05160e05161010051610120516101405161016051610180516101a0516132be61079b600039600081816103b101528181610d85015281816118450152818161188601528181611abc01528181611d1b01528181611fc4015281816120aa0152818161217e015281816127550152612c6a0152600081816104bb015261266f0152600081816105f601528181611a1401528181611e010152612b650152600081816106900152818161156a01528181611beb01528181611d840152611e9401526000818161054f0152818161084801528181610aeb01528181610c3101528181610cf801528181610dac01528181610e280152818161123d01528181611b3b01528181611f2701528181611ff8015281816120d40152818161214d015281816127220152612c3901526000818161035f0152818161099301528181610a2401528181610fa8015281816110a50152818161119701528181611219015281816112f60152818161151c015281816117450152818161198701528181611b17015281816122900152818161231e015261281801526000818161042d01528181610e9301528181610ee801528181611374015281816123c201526126a901526000818161061d015281816108010152612d0b0152600081816106fb0152610f810152600081816105ab01528181610ec201528181611901015261194201526132be6000f3fe608060405234801561001057600080fd5b50600436106102a05760003560e01c8063787a08a611610167578063babe7c74116100ce578063d8dfeb4511610087578063d8dfeb451461068b578063d9caed12146106b2578063e5a4bed3146106c5578063f2fde38b146106cd578063f37c2ecf146106e0578063f3f480d9146106f657600080fd5b8063babe7c74146105f1578063be9a655514610618578063c2b6b58c1461063f578063c392f7661461065c578063c54a89ca14610665578063cfb636f01461067857600080fd5b80639de2f796116101205780639de2f7961461058a578063a035b1fe1461059d578063a4d66daf146105a6578063a8a3e31d146105cd578063b8e2426c146105d5578063ba5d3078146105e857600080fd5b8063787a08a6146104dd5780637b3baab4146104ee5780637ccd4f71146104ff57806382b8eaf51461054a5780638da5cb5b146105715780638ea875f31461058257600080fd5b8063371fd8e61161020b5780635be980f5116101c45780635be980f5146104625780636d4749fa146104755780636f871cec14610488578063715018a61461049b57806372bf079e146104a3578063730d48b7146104b657600080fd5b8063371fd8e6146103995780633a7c29fb146103ac57806340c10f19146103e75780634665096d146103fa57806346c715fa1461042857806349746f101461044f57600080fd5b806324e657fe1161025d57806324e657fe1461030b57806329d93d67146103145780632a37eeae1461031c578063329864aa14610324578063350c35e914610347578063365a86fc1461035a57600080fd5b80630e49d77e146102a557806313a06782146102af57806314a6bf0f146102ca5780631bbea34c146102d25780631dbcff26146102e5578063211d7983146102f8575b600080fd5b6102ad61071d565b005b6102b76107e6565b6040519081526020015b60405180910390f35b6102b76107f5565b6102ad6102e0366004612e13565b6107ff565b6102ad6102f3366004612ecb565b610988565b6102ad610306366004612ef7565b610a19565b6102b760035481565b6102b7610e6d565b6102b7610e87565b61032c610f68565b6040805192835264ffffffffff9091166020830152016102c1565b6102ad610355366004612ecb565b610fa6565b6103817f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016102c1565b6102b76103a7366004612f2c565b611054565b6103d37f000000000000000000000000000000000000000000000000000000000000000081565b60405162ffffff90911681526020016102c1565b6102ad6103f5366004612ecb565b6110a3565b60055461041290600160281b900464ffffffffff1681565b60405164ffffffffff90911681526020016102c1565b6103817f000000000000000000000000000000000000000000000000000000000000000081565b6102ad61045d366004612f2c565b61118c565b6102ad610470366004612f2c565b6111fc565b6102ad610483366004612f58565b6112eb565b6102ad610496366004612f91565b611544565b6102ad6116d3565b6102ad6104b1366004612f2c565b6116e5565b6103d37f000000000000000000000000000000000000000000000000000000000000000081565b6005546104129064ffffffffff1681565b6008546104129064ffffffffff1681565b61051261050d366004612f2c565b611734565b604080516001600160a01b039096168652602086019490945292840191909152606083015263ffffffff16608082015260a0016102c1565b6103817f000000000000000000000000000000000000000000000000000000000000000081565b6000546001600160a01b0316610381565b6102b7611871565b6102b7610598366004612f2c565b61187e565b6102b760015481565b6102b77f000000000000000000000000000000000000000000000000000000000000000081565b6102b76118b0565b6102ad6105e3366004612fbd565b61197c565b6102b760065481565b6102b77f000000000000000000000000000000000000000000000000000000000000000081565b6104127f000000000000000000000000000000000000000000000000000000000000000081565b600554600160501b900460ff1660405190151581526020016102c1565b6102b760075481565b6102b7610673366004612f2c565b611ab1565b6102ad610686366004612f2c565b611afa565b6103817f000000000000000000000000000000000000000000000000000000000000000081565b6102ad6106c0366004612fdf565b611be1565b6102b7611cc7565b6102ad6106db366004613020565b611cd1565b6005546103d390600160581b900462ffffff1681565b6104127f000000000000000000000000000000000000000000000000000000000000000081565b6003541561073e5760405163d26e2de960e01b815260040160405180910390fd5b60055464ffffffffff16421161076757604051631c02820f60e21b815260040160405180910390fd5b600554600160281b900464ffffffffff1642106107b9576005546040516238ddd760e41b815264ffffffffff4281166004830152600160281b9092049190911660248201526044015b60405180910390fd5b600554600160501b900460ff16156107e457604051631cdde67b60e01b815260040160405180910390fd5b565b60006107f0611d0c565b905090565b60006107f0611d4c565b7f000000000000000000000000000000000000000000000000000000000000000064ffffffffff1642106108465760405163ecdd1c2960e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663cd3293de6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108a4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108c8919061303d565b6001600160a01b031663352e3a833386866040518463ffffffff1660e01b81526004016108f79392919061305a565b60006040518083038186803b15801561090f57600080fd5b505afa158015610923573d6000803e3d6000fd5b5050505061093f6005805460ff60501b1916600160501b179055565b336001600160a01b03167faca80c800ec0d2aa9d9d31b7f886a1dd3067d4676abc637626a18ffb9381653d838360405161097a9291906130b8565b60405180910390a250505050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146109d1576040516313bd2e8360e31b815260040160405180910390fd5b60006109dd8383611d56565b600154600654604080518481526020810193909352820152909150600080516020613269833981519152906060015b60405180910390a1505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610a62576040516313bd2e8360e31b815260040160405180910390fd5b600554600160281b900464ffffffffff16421015610a93576040516302de694d60e41b815260040160405180910390fd5b60035415610ab45760405163d26e2de960e01b815260040160405180910390fd5b6000610abe611e46565b600654610acb91906130fd565b90506000610ad98585611d56565b905081600003610be7578215610ba5577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166323b872dd86610b2b6000546001600160a01b031690565b6040516001600160e01b031960e085901b1681526001600160a01b03928316600482015291166024820152604481018690526064016020604051808303816000875af1158015610b7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ba39190613110565b505b600080516020613269833981519152610bbc611e7c565b6001546006546040805193845260208401929092529082015260600160405180910390a15050505050565b610bf18584611ee3565b9250610bfd8584611fa6565b925080158015610c1c57506000600754600654610c1a91906130fd565b115b15610e20578215610c2f57610c2f613132565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d1fa5e9830600754600654610c6f91906130fd565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b158015610cb557600080fd5b505af1158015610cc9573d6000803e3d6000fd5b5050505060006007541115610d675760075460405163375edc7760e11b815230600482015260248101919091527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636ebdb8ee90604401600060405180830381600087803b158015610d4457600080fd5b505af1158015610d58573d6000803e3d6000fd5b50505050610d67600754612241565b6006546040516363b20c3360e11b8152600481019190915262ffffff7f00000000000000000000000000000000000000000000000000000000000000001660248201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063c764186690604401600060405180830381600087803b158015610df857600080fd5b505af1158015610e0c573d6000803e3d6000fd5b50505050610e1b600654612395565b610ba5565b8215610ba5577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166323b872dd86610b2b6000546001600160a01b031690565b505050565b60006107f0610e7a611e46565b6006546103a791906130fd565b60006001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003610ee6576002546107f0907f0000000000000000000000000000000000000000000000000000000000000000613148565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a8a3e31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f44573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107f0919061315b565b600080610f7e610f76611e7c565b600154612438565b927f000000000000000000000000000000000000000000000000000000000000000092509050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663f09e9e3a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611004573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611028919061303d565b6001600160a01b0316336001600160a01b03161461104857611048612493565b60006109dd83836124c0565b60008061106083612527565b9050600080516020613269833981519152611079611e7c565b6001546006546040805193845260208401929092529082015260600160405180910390a192915050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663f09e9e3a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611101573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611125919061303d565b6001600160a01b0316336001600160a01b03161461114557611145612493565b600061114f611e7c565b905061115c838383612565565b60015460065460408051848152602081019390935282015260008051602061326983398151915290606001610a0c565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146111d5576040516313bd2e8360e31b815260040160405180910390fd5b80600360008282546111e79190613148565b909155506111f99050620151806127d4565b50565b60405163aa5dd7f160e01b81523360048201526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116917f00000000000000000000000000000000000000000000000000000000000000009091169063aa5dd7f190602401602060405180830381865afa158015611286573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112aa919061303d565b6001600160a01b0316146112d1576040516313bd2e8360e31b815260040160405180910390fd5b80600260008282546112e39190613148565b909155505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611334576040516313bd2e8360e31b815260040160405180910390fd5b600554600160281b900464ffffffffff16156113625760405162dc149f60e41b815260040160405180910390fd5b428164ffffffffff16108061140557507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316634665096d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113f49190613174565b64ffffffffff168164ffffffffff16115b1561142357604051637d9533a960e11b815260040160405180910390fd5b806005806101000a81548164ffffffffff021916908364ffffffffff160217905550816001600160a01b031663a035b1fe6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611483573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114a7919061315b565b600181905550611517826001600160a01b031663730d48b76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156114ee573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115129190613191565b612815565b6115407f0000000000000000000000000000000000000000000000000000000000000000612924565b5050565b61154c612493565b6000611556611e7c565b905080831115611615576001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166323b872dd333061159b8588613148565b6040516001600160e01b031960e086901b1681526001600160a01b03938416600482015292909116602483015260448201526064016020604051808303816000875af11580156115ef573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116139190613110565b505b60065484101561164d576000611629611e46565b60065461163691906130fd565b905061164a6116458683613148565b612527565b50505b8083101561166a57611668336116638584613148565b6124c0565b505b60065484111561168c5761168c33600654866116869190613148565b85612565565b600154821461169e5761169e82612974565b60408051848152602081018490529081018590526000805160206132698339815191529060600160405180910390a150505050565b6116db612493565b6107e46000612924565b6116ed612493565b6116f681612974565b60008051602061326983398151915261170d611e7c565b6001546006546040805193845260208401929092529082015260600160405180910390a150565b600080808080336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611783576040516313bd2e8360e31b815260040160405180910390fd5b61178b611e46565b50856003600082825461179e9190613148565b90915550600090506117ae611e7c565b9050868110156117bc578096505b600081156117e25781886007546117d391906131b6565b6117dd91906131cd565b6117e5565b60005b90506000821561180d5782896006546117fe91906131b6565b61180891906131cd565b611810565b60005b905061181b82612241565b61182481612395565b6118306203f4806127d4565b6000546001600160a01b0316999097509095507f000000000000000000000000000000000000000000000000000000000000000062ffffff16945092505050565b60006107f0610f76611e7c565b60006118aa827f0000000000000000000000000000000000000000000000000000000000000000612a80565b92915050565b600080670de0b6b3a76400006001546118c7611e7c565b6118d191906131b6565b6118db91906131cd565b9050600081600654116118fa576006546118f59083613148565b6118fd565b60005b90507f00000000000000000000000000000000000000000000000000000000000000008160025461192e91906130fd565b1061193c5760009250505090565b806002547f000000000000000000000000000000000000000000000000000000000000000061196b9190613148565b6119759190613148565b9250505090565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146119c5576040516313bd2e8360e31b815260040160405180910390fd5b600554600160281b900464ffffffffff164210611a12576005546040516238ddd760e41b815264ffffffffff4281166004830152600160281b9092049190911660248201526044016107b0565b7f000000000000000000000000000000000000000000000000000000000000000082108015611a475750611a44611e7c565b82105b15611a6557604051633c80636b60e21b815260040160405180910390fd5b81600003611a8657604051633c80636b60e21b815260040160405180910390fd5b600354600003611a965760048190555b8160036000828254611aa891906130fd565b90915550505050565b6000620f4240611ae17f0000000000000000000000000000000000000000000000000000000000000000826131ef565b611af09062ffffff16846131b6565b6118aa91906131cd565b60405163aa5dd7f160e01b81523360048201526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116917f00000000000000000000000000000000000000000000000000000000000000009091169063aa5dd7f190602401602060405180830381865afa158015611b84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ba8919061303d565b6001600160a01b031614611bcf576040516313bd2e8360e31b815260040160405180910390fd5b80600260008282546112e391906130fd565b611be9612493565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b031603611c2c57610e688282610fa6565b6000611c36611e7c565b60405163a9059cbb60e01b81526001600160a01b038581166004830152602482018590529192509085169063a9059cbb906044016020604051808303816000875af1158015611c89573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cad9190613110565b50611cb6611e7c565b8114611cc157600080fd5b50505050565b60006107f0612ad6565b611cd9612493565b6001600160a01b038116611d0357604051631e4fbdf760e01b8152600060048201526024016107b0565b6111f981612924565b6000611d3f611d19612ad6565b7f0000000000000000000000000000000000000000000000000000000000000000612a80565b6006546107f091906130fd565b6000611d3f612ad6565b60008115611df35760405163a9059cbb60e01b81526001600160a01b038481166004830152602482018490527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906044016020604051808303816000875af1158015611dcd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611df19190613110565b505b6000611dfd611e7c565b90507f0000000000000000000000000000000000000000000000000000000000000000811015611e3f57611e3f6005805460ff60501b1916600160501b179055565b9392505050565b6000611e50612ad6565b9050600754811115611e625760078190555b6008805464ffffffffff19164264ffffffffff1617905590565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015610f44573d6000803e3d6000fd5b6000808260075411611ef757600754611ef9565b825b90508015611f9e5760405163375edc7760e11b81526001600160a01b038581166004830152602482018390527f00000000000000000000000000000000000000000000000000000000000000001690636ebdb8ee90604401600060405180830381600087803b158015611f6b57600080fd5b505af1158015611f7f573d6000803e3d6000fd5b50505050611f8c81612241565b611f968184613148565b9150506118aa565b509092915050565b6006546040516302dc1ca760e31b8152600481019190915262ffffff7f000000000000000000000000000000000000000000000000000000000000000016602482015260009081906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906316e0e53890604401602060405180830381865afa15801561203f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612063919061315b565b90506000816006546120759190613148565b905060008185116120865784612088565b815b9050801561223757604051633824f22960e21b81526004810182905262ffffff7f00000000000000000000000000000000000000000000000000000000000000001660248201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063e093c8a490604401602060405180830381865afa158015612123573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612147919061315b565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663315f3e7289847f00000000000000000000000000000000000000000000000000000000000000006040518463ffffffff1660e01b81526004016121bb9392919061320a565b6020604051808303816000875af11580156121da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121fe919061315b565b905061220a8383613148565b811461221857612218613132565b61222182612395565b61222b8388613148565b955050505050506118aa565b5092949350505050565b600754811115612274576007546122589082613148565b604051635795d46960e11b81526004016107b091815260200190565b6040516301ffc9a760e01b8152632464e41b60e21b60048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906301ffc9a790602401602060405180830381865afa1580156122df573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123039190613110565b1561238357604051637d0ea02d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690637d0ea02d90602401600060405180830381600087803b15801561236a57600080fd5b505af115801561237e573d6000803e3d6000fd5b505050505b80600760008282546112e39190613148565b6006548111156123ac576006546122589082613148565b604051635be980f560e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635be980f590602401600060405180830381600087803b15801561240e57600080fd5b505af1158015612422573d6000803e3d6000fd5b5050505080600660008282546112e39190613148565b6003546000901561244c57506004546118aa565b8260000361245b5750806118aa565b600083670de0b6b3a764000061246f611d0c565b61247991906131b6565b61248391906131cd565b9050828110611f9e579392505050565b6000546001600160a01b031633146107e45760405163118cdaa760e01b81523360048201526024016107b0565b60055460009064ffffffffff1642116124ec57604051631c02820f60e21b815260040160405180910390fd5b6003541561250d5760405163d26e2de960e01b815260040160405180910390fd5b60006125198484611d56565b9050611e3f81600154612b61565b6000612531611e46565b508160000361254257506000919050565b8161254d3382611ee3565b90506125593382612c01565b9050611e3f8184613148565b600354156125865760405163d26e2de960e01b815260040160405180910390fd5b60055464ffffffffff1642116125af57604051631c02820f60e21b815260040160405180910390fd5b600554600160281b900464ffffffffff1642106125fc576005546040516238ddd760e41b815264ffffffffff4281166004830152600160281b9092049190911660248201526044016107b0565b600554600160501b900460ff161561262757604051631cdde67b60e01b815260040160405180910390fd5b61262f610e87565b821115612661578161263f610e87565b604051634779077960e11b8152600481019290925260248201526044016107b0565b612669611e46565b506126937f0000000000000000000000000000000000000000000000000000000000000000612815565b604051630cfb636f60e41b8152600481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063cfb636f090602401600060405180830381600087803b1580156126f557600080fd5b505af1158015612709573d6000803e3d6000fd5b505060405163165203b760e31b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016925063b2901db8915061277d90869086907f00000000000000000000000000000000000000000000000000000000000000009060040161320a565b600060405180830381600087803b15801561279757600080fd5b505af11580156127ab573d6000803e3d6000fd5b5050505081600660008282546127c191906130fd565b92505081905550610e6881600154612b61565b60006127e08242613230565b60055490915064ffffffffff9081169082161115611540576005805464ffffffffff831664ffffffffff199091161790555050565b807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663664e97046040518163ffffffff1660e01b8152600401602060405180830381865afa158015612874573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612898919061303d565b6001600160a01b03166306a7b3766040518163ffffffff1660e01b8152600401602060405180830381865afa1580156128d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128f99190613191565b612903919061324d565b6005600b6101000a81548162ffffff021916908362ffffff16021790555050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600354156129955760405163d26e2de960e01b815260040160405180910390fd5b600554600160281b900464ffffffffff1642106129e2576005546040516238ddd760e41b815264ffffffffff4281166004830152600160281b9092049190911660248201526044016107b0565b600554600160501b900460ff1615612a0d57604051631cdde67b60e01b815260040160405180910390fd5b60055464ffffffffff164211612a3657604051631c02820f60e21b815260040160405180910390fd5b600154811115612a5157612a4c6203f4806127d4565b612a62565b612a62612a5c611e7c565b82612b61565b6111f981612a6e610e87565b600654612a7b91906130fd565b612cfd565b60008215612acd57612a9582620f42406131ef565b62ffffff166001612aa985620f42406131b6565b612ab39190613148565b612abd91906131cd565b612ac89060016130fd565b611e3f565b60009392505050565b600754600854429064ffffffffff1681118015612af557506000600654115b15612b5d57600854600090612b119064ffffffffff1683613148565b9050651cae8c13e000816005600b9054906101000a900462ffffff1662ffffff16600654612b3f91906131b6565b612b4991906131b6565b612b5391906131cd565b61197590846130fd565b5090565b60007f00000000000000000000000000000000000000000000000000000000000000008310612b905782612b93565b60005b90506000612b9f611d0c565b9050612bb3670de0b6b3a7640000826131b6565b612bbd84846131b6565b1015611cc157612bcd83836131b6565b612bdf670de0b6b3a7640000836131b6565b604051632c1f8ef160e21b8152600481019290925260248201526044016107b0565b6000808260065411612c1557600654612c17565b825b90508015611f9e576040516318af9f3960e11b81526000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063315f3e7290612c9290889086907f00000000000000000000000000000000000000000000000000000000000000009060040161320a565b6020604051808303816000875af1158015612cb1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cd5919061315b565b9050612ce082612395565b612cea8183613148565b612cf49085613148565b925050506118aa565b6000612d07611e7c565b90507f000000000000000000000000000000000000000000000000000000000000000064ffffffffff164210158015612d4c5750600154612d499060026131b6565b83115b15612d8357826001546002612d6191906131b6565b6040516387ebe85d60e01b8152600481019290925260248201526044016107b0565b612d95670de0b6b3a7640000836131b6565b612d9f82856131b6565b1115612dc3578281612db9670de0b6b3a7640000856131b6565b612d6191906131cd565b5050600155565b60008083601f840112612ddc57600080fd5b50813567ffffffffffffffff811115612df457600080fd5b602083019150836020828501011115612e0c57600080fd5b9250929050565b60008060008060408587031215612e2957600080fd5b843567ffffffffffffffff811115612e4057600080fd5b8501601f81018713612e5157600080fd5b803567ffffffffffffffff811115612e6857600080fd5b8760208260051b8401011115612e7d57600080fd5b60209182019550935085013567ffffffffffffffff811115612e9e57600080fd5b612eaa87828801612dca565b95989497509550505050565b6001600160a01b03811681146111f957600080fd5b60008060408385031215612ede57600080fd5b8235612ee981612eb6565b946020939093013593505050565b600080600060608486031215612f0c57600080fd5b8335612f1781612eb6565b95602085013595506040909401359392505050565b600060208284031215612f3e57600080fd5b5035919050565b64ffffffffff811681146111f957600080fd5b60008060408385031215612f6b57600080fd5b8235612f7681612eb6565b91506020830135612f8681612f45565b809150509250929050565b600080600060608486031215612fa657600080fd5b505081359360208301359350604090920135919050565b60008060408385031215612fd057600080fd5b50508035926020909101359150565b600080600060608486031215612ff457600080fd5b8335612fff81612eb6565b9250602084013561300f81612eb6565b929592945050506040919091013590565b60006020828403121561303257600080fd5b8135611e3f81612eb6565b60006020828403121561304f57600080fd5b8151611e3f81612eb6565b6001600160a01b0384168152604060208201819052810182905260008360608301825b858110156130ad57823561309081612eb6565b6001600160a01b031682526020928301929091019060010161307d565b509695505050505050565b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b634e487b7160e01b600052601160045260246000fd5b808201808211156118aa576118aa6130e7565b60006020828403121561312257600080fd5b81518015158114611e3f57600080fd5b634e487b7160e01b600052600160045260246000fd5b818103818111156118aa576118aa6130e7565b60006020828403121561316d57600080fd5b5051919050565b60006020828403121561318657600080fd5b8151611e3f81612f45565b6000602082840312156131a357600080fd5b815162ffffff81168114611e3f57600080fd5b80820281158282048414176118aa576118aa6130e7565b6000826131ea57634e487b7160e01b600052601260045260246000fd5b500490565b62ffffff82811682821603908111156118aa576118aa6130e7565b6001600160a01b03939093168352602083019190915262ffffff16604082015260600190565b64ffffffffff81811683821601908111156118aa576118aa6130e7565b62ffffff81811683821601908111156118aa576118aa6130e756fe9483a26ad376f30b5199a79e75df3bb05158c4ee32a348f53e83245a5e50c86ea26469706673582212209a1975e04fb13fc1ca52e414c56b5c239b9ac598c02c1ac429d1dfc9e289acd464736f6c634300081a0033a26469706673582212202f943f0c1e50fc77fe44a52efa4244454fe0fd30125d7d6aa6bf364d2f4dad7664736f6c634300081a0033","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/0x167144d66AC1D02EAAFCa3649ef3305ea31Ee5A8/","decoded_constructor_args":null,"compiler_version":"0.8.26+commit.8a97fa7a","is_verified_via_verifier_alliance":false,"verified_at":"2026-03-14T09:15:08.668445Z","implementations":[],"proxy_type":null,"external_libraries":[],"creation_bytecode":"0x6080604052348015600f57600080fd5b50613ebb8061001f6000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80635d824f761461003b578063b3e891801461006a575b600080fd5b61004e61004936600461029e565b61007d565b6040516001600160a01b03909116815260200160405180910390f35b61004e61007836600461035b565b6100d9565b60008b338c8c8c8c8c8c8c8c8c8c6040516100979061024c565b6100ac9c9b9a9998979695949392919061037f565b604051809103906000f0801580156100c8573d6000803e3d6000fd5b509c9b505050505050505050505050565b600080829050806001600160a01b0316630e49d77e6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561011a57600080fd5b505af115801561012e573d6000803e3d6000fd5b50505050600061019e826001600160a01b03166346c715fa6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610175573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610199919061040f565b6101a6565b949350505050565b6000808260601b9050604051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b81528160148201526e5af43d82803e903d91602b57fd5bf360881b60288201526037816000f09250506001600160a01b0382166102465760405162461bcd60e51b8152602060048201526016602482015275115490cc4c4d8dce8818dc99585d194819985a5b195960521b604482015260640160405180910390fd5b50919050565b613a598061042d83390190565b6001600160a01b038116811461026e57600080fd5b50565b803564ffffffffff8116811461028657600080fd5b919050565b803562ffffff8116811461028657600080fd5b60008060008060008060008060008060006101608c8e0312156102c057600080fd5b8b356102cb81610259565b9a5060208c01356102db81610259565b995060408c01356102eb81610259565b985060608c0135975060808c0135965061030760a08d01610271565b955061031560c08d01610271565b945061032360e08d01610271565b93506103326101008d0161028b565b92506101208c013591506103496101408d0161028b565b90509295989b509295989b9093969950565b60006020828403121561036d57600080fd5b813561037881610259565b9392505050565b6001600160a01b038d811682528c811660208301528b811660408301528a1660608201526080810189905260a0810188905264ffffffffff87811660c0830152861660e0820152610180810164ffffffffff861661010083015262ffffff8516610120830152836101408301526103fe61016083018462ffffff169052565b9d9c50505050505050505050505050565b60006020828403121561042157600080fd5b81516103788161025956fe6101c060405234801561001157600080fd5b50604051613a59380380613a59833981016040819052610030916103d8565b8b6001600160a01b03811661006057604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b6100698161012f565b503060e0526001600160a01b038b8116610100528a81166101205289166101405262ffffff8084166101805281166101a05261016088905264ffffffffff841660a0526100b686426104c2565b64ffffffffff1660c08190526005805464ffffffffff1916821790556100dd9086906104c2565b6005805464ffffffffff92909216650100000000000264ffffffffff60281b199092169190911790556080879052610115828861017f565b61011e8361022e565b505050505050505050505050610591565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000610189610320565b905060c05164ffffffffff1642101580156101b057506001546101ad9060026104e5565b83115b156101e7578260015460026101c591906104e5565b6040516387ebe85d60e01b815260048101929092526024820152604401610057565b6101f9670de0b6b3a7640000836104e5565b61020382856104e5565b111561022757828161021d670de0b6b3a7640000856104e5565b6101c591906104fc565b5050600155565b80610100516001600160a01b031663664e97046040518163ffffffff1660e01b8152600401602060405180830381865afa158015610270573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610294919061051e565b6001600160a01b03166306a7b3766040518163ffffffff1660e01b8152600401602060405180830381865afa1580156102d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102f59190610542565b6102ff919061055d565b6005600b6101000a81548162ffffff021916908362ffffff16021790555050565b610140516040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa15801561036a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061038e9190610578565b905090565b6001600160a01b03811681146103a857600080fd5b50565b805164ffffffffff811681146103c057600080fd5b919050565b805162ffffff811681146103c057600080fd5b6000806000806000806000806000806000806101808d8f0312156103fb57600080fd5b8c5161040681610393565b60208e0151909c5061041781610393565b60408e0151909b5061042881610393565b60608e0151909a5061043981610393565b60808e015160a08f0151919a509850965061045660c08e016103ab565b955061046460e08e016103ab565b94506104736101008e016103ab565b93506104826101208e016103c5565b6101408e0151909350915061049a6101608e016103c5565b90509295989b509295989b509295989b565b634e487b7160e01b600052601160045260246000fd5b64ffffffffff81811683821601908111156104df576104df6104ac565b92915050565b80820281158282048414176104df576104df6104ac565b60008261051957634e487b7160e01b600052601260045260246000fd5b500490565b60006020828403121561053057600080fd5b815161053b81610393565b9392505050565b60006020828403121561055457600080fd5b61053b826103c5565b62ffffff81811683821601908111156104df576104df6104ac565b60006020828403121561058a57600080fd5b5051919050565b60805160a05160c05160e05161010051610120516101405161016051610180516101a0516132be61079b600039600081816103b101528181610d85015281816118450152818161188601528181611abc01528181611d1b01528181611fc4015281816120aa0152818161217e015281816127550152612c6a0152600081816104bb015261266f0152600081816105f601528181611a1401528181611e010152612b650152600081816106900152818161156a01528181611beb01528181611d840152611e9401526000818161054f0152818161084801528181610aeb01528181610c3101528181610cf801528181610dac01528181610e280152818161123d01528181611b3b01528181611f2701528181611ff8015281816120d40152818161214d015281816127220152612c3901526000818161035f0152818161099301528181610a2401528181610fa8015281816110a50152818161119701528181611219015281816112f60152818161151c015281816117450152818161198701528181611b17015281816122900152818161231e015261281801526000818161042d01528181610e9301528181610ee801528181611374015281816123c201526126a901526000818161061d015281816108010152612d0b0152600081816106fb0152610f810152600081816105ab01528181610ec201528181611901015261194201526132be6000f3fe608060405234801561001057600080fd5b50600436106102a05760003560e01c8063787a08a611610167578063babe7c74116100ce578063d8dfeb4511610087578063d8dfeb451461068b578063d9caed12146106b2578063e5a4bed3146106c5578063f2fde38b146106cd578063f37c2ecf146106e0578063f3f480d9146106f657600080fd5b8063babe7c74146105f1578063be9a655514610618578063c2b6b58c1461063f578063c392f7661461065c578063c54a89ca14610665578063cfb636f01461067857600080fd5b80639de2f796116101205780639de2f7961461058a578063a035b1fe1461059d578063a4d66daf146105a6578063a8a3e31d146105cd578063b8e2426c146105d5578063ba5d3078146105e857600080fd5b8063787a08a6146104dd5780637b3baab4146104ee5780637ccd4f71146104ff57806382b8eaf51461054a5780638da5cb5b146105715780638ea875f31461058257600080fd5b8063371fd8e61161020b5780635be980f5116101c45780635be980f5146104625780636d4749fa146104755780636f871cec14610488578063715018a61461049b57806372bf079e146104a3578063730d48b7146104b657600080fd5b8063371fd8e6146103995780633a7c29fb146103ac57806340c10f19146103e75780634665096d146103fa57806346c715fa1461042857806349746f101461044f57600080fd5b806324e657fe1161025d57806324e657fe1461030b57806329d93d67146103145780632a37eeae1461031c578063329864aa14610324578063350c35e914610347578063365a86fc1461035a57600080fd5b80630e49d77e146102a557806313a06782146102af57806314a6bf0f146102ca5780631bbea34c146102d25780631dbcff26146102e5578063211d7983146102f8575b600080fd5b6102ad61071d565b005b6102b76107e6565b6040519081526020015b60405180910390f35b6102b76107f5565b6102ad6102e0366004612e13565b6107ff565b6102ad6102f3366004612ecb565b610988565b6102ad610306366004612ef7565b610a19565b6102b760035481565b6102b7610e6d565b6102b7610e87565b61032c610f68565b6040805192835264ffffffffff9091166020830152016102c1565b6102ad610355366004612ecb565b610fa6565b6103817f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016102c1565b6102b76103a7366004612f2c565b611054565b6103d37f000000000000000000000000000000000000000000000000000000000000000081565b60405162ffffff90911681526020016102c1565b6102ad6103f5366004612ecb565b6110a3565b60055461041290600160281b900464ffffffffff1681565b60405164ffffffffff90911681526020016102c1565b6103817f000000000000000000000000000000000000000000000000000000000000000081565b6102ad61045d366004612f2c565b61118c565b6102ad610470366004612f2c565b6111fc565b6102ad610483366004612f58565b6112eb565b6102ad610496366004612f91565b611544565b6102ad6116d3565b6102ad6104b1366004612f2c565b6116e5565b6103d37f000000000000000000000000000000000000000000000000000000000000000081565b6005546104129064ffffffffff1681565b6008546104129064ffffffffff1681565b61051261050d366004612f2c565b611734565b604080516001600160a01b039096168652602086019490945292840191909152606083015263ffffffff16608082015260a0016102c1565b6103817f000000000000000000000000000000000000000000000000000000000000000081565b6000546001600160a01b0316610381565b6102b7611871565b6102b7610598366004612f2c565b61187e565b6102b760015481565b6102b77f000000000000000000000000000000000000000000000000000000000000000081565b6102b76118b0565b6102ad6105e3366004612fbd565b61197c565b6102b760065481565b6102b77f000000000000000000000000000000000000000000000000000000000000000081565b6104127f000000000000000000000000000000000000000000000000000000000000000081565b600554600160501b900460ff1660405190151581526020016102c1565b6102b760075481565b6102b7610673366004612f2c565b611ab1565b6102ad610686366004612f2c565b611afa565b6103817f000000000000000000000000000000000000000000000000000000000000000081565b6102ad6106c0366004612fdf565b611be1565b6102b7611cc7565b6102ad6106db366004613020565b611cd1565b6005546103d390600160581b900462ffffff1681565b6104127f000000000000000000000000000000000000000000000000000000000000000081565b6003541561073e5760405163d26e2de960e01b815260040160405180910390fd5b60055464ffffffffff16421161076757604051631c02820f60e21b815260040160405180910390fd5b600554600160281b900464ffffffffff1642106107b9576005546040516238ddd760e41b815264ffffffffff4281166004830152600160281b9092049190911660248201526044015b60405180910390fd5b600554600160501b900460ff16156107e457604051631cdde67b60e01b815260040160405180910390fd5b565b60006107f0611d0c565b905090565b60006107f0611d4c565b7f000000000000000000000000000000000000000000000000000000000000000064ffffffffff1642106108465760405163ecdd1c2960e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663cd3293de6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108a4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108c8919061303d565b6001600160a01b031663352e3a833386866040518463ffffffff1660e01b81526004016108f79392919061305a565b60006040518083038186803b15801561090f57600080fd5b505afa158015610923573d6000803e3d6000fd5b5050505061093f6005805460ff60501b1916600160501b179055565b336001600160a01b03167faca80c800ec0d2aa9d9d31b7f886a1dd3067d4676abc637626a18ffb9381653d838360405161097a9291906130b8565b60405180910390a250505050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146109d1576040516313bd2e8360e31b815260040160405180910390fd5b60006109dd8383611d56565b600154600654604080518481526020810193909352820152909150600080516020613269833981519152906060015b60405180910390a1505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610a62576040516313bd2e8360e31b815260040160405180910390fd5b600554600160281b900464ffffffffff16421015610a93576040516302de694d60e41b815260040160405180910390fd5b60035415610ab45760405163d26e2de960e01b815260040160405180910390fd5b6000610abe611e46565b600654610acb91906130fd565b90506000610ad98585611d56565b905081600003610be7578215610ba5577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166323b872dd86610b2b6000546001600160a01b031690565b6040516001600160e01b031960e085901b1681526001600160a01b03928316600482015291166024820152604481018690526064016020604051808303816000875af1158015610b7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ba39190613110565b505b600080516020613269833981519152610bbc611e7c565b6001546006546040805193845260208401929092529082015260600160405180910390a15050505050565b610bf18584611ee3565b9250610bfd8584611fa6565b925080158015610c1c57506000600754600654610c1a91906130fd565b115b15610e20578215610c2f57610c2f613132565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d1fa5e9830600754600654610c6f91906130fd565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b158015610cb557600080fd5b505af1158015610cc9573d6000803e3d6000fd5b5050505060006007541115610d675760075460405163375edc7760e11b815230600482015260248101919091527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636ebdb8ee90604401600060405180830381600087803b158015610d4457600080fd5b505af1158015610d58573d6000803e3d6000fd5b50505050610d67600754612241565b6006546040516363b20c3360e11b8152600481019190915262ffffff7f00000000000000000000000000000000000000000000000000000000000000001660248201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063c764186690604401600060405180830381600087803b158015610df857600080fd5b505af1158015610e0c573d6000803e3d6000fd5b50505050610e1b600654612395565b610ba5565b8215610ba5577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166323b872dd86610b2b6000546001600160a01b031690565b505050565b60006107f0610e7a611e46565b6006546103a791906130fd565b60006001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003610ee6576002546107f0907f0000000000000000000000000000000000000000000000000000000000000000613148565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a8a3e31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f44573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107f0919061315b565b600080610f7e610f76611e7c565b600154612438565b927f000000000000000000000000000000000000000000000000000000000000000092509050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663f09e9e3a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611004573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611028919061303d565b6001600160a01b0316336001600160a01b03161461104857611048612493565b60006109dd83836124c0565b60008061106083612527565b9050600080516020613269833981519152611079611e7c565b6001546006546040805193845260208401929092529082015260600160405180910390a192915050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663f09e9e3a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611101573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611125919061303d565b6001600160a01b0316336001600160a01b03161461114557611145612493565b600061114f611e7c565b905061115c838383612565565b60015460065460408051848152602081019390935282015260008051602061326983398151915290606001610a0c565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146111d5576040516313bd2e8360e31b815260040160405180910390fd5b80600360008282546111e79190613148565b909155506111f99050620151806127d4565b50565b60405163aa5dd7f160e01b81523360048201526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116917f00000000000000000000000000000000000000000000000000000000000000009091169063aa5dd7f190602401602060405180830381865afa158015611286573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112aa919061303d565b6001600160a01b0316146112d1576040516313bd2e8360e31b815260040160405180910390fd5b80600260008282546112e39190613148565b909155505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611334576040516313bd2e8360e31b815260040160405180910390fd5b600554600160281b900464ffffffffff16156113625760405162dc149f60e41b815260040160405180910390fd5b428164ffffffffff16108061140557507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316634665096d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113f49190613174565b64ffffffffff168164ffffffffff16115b1561142357604051637d9533a960e11b815260040160405180910390fd5b806005806101000a81548164ffffffffff021916908364ffffffffff160217905550816001600160a01b031663a035b1fe6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611483573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114a7919061315b565b600181905550611517826001600160a01b031663730d48b76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156114ee573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115129190613191565b612815565b6115407f0000000000000000000000000000000000000000000000000000000000000000612924565b5050565b61154c612493565b6000611556611e7c565b905080831115611615576001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166323b872dd333061159b8588613148565b6040516001600160e01b031960e086901b1681526001600160a01b03938416600482015292909116602483015260448201526064016020604051808303816000875af11580156115ef573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116139190613110565b505b60065484101561164d576000611629611e46565b60065461163691906130fd565b905061164a6116458683613148565b612527565b50505b8083101561166a57611668336116638584613148565b6124c0565b505b60065484111561168c5761168c33600654866116869190613148565b85612565565b600154821461169e5761169e82612974565b60408051848152602081018490529081018590526000805160206132698339815191529060600160405180910390a150505050565b6116db612493565b6107e46000612924565b6116ed612493565b6116f681612974565b60008051602061326983398151915261170d611e7c565b6001546006546040805193845260208401929092529082015260600160405180910390a150565b600080808080336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611783576040516313bd2e8360e31b815260040160405180910390fd5b61178b611e46565b50856003600082825461179e9190613148565b90915550600090506117ae611e7c565b9050868110156117bc578096505b600081156117e25781886007546117d391906131b6565b6117dd91906131cd565b6117e5565b60005b90506000821561180d5782896006546117fe91906131b6565b61180891906131cd565b611810565b60005b905061181b82612241565b61182481612395565b6118306203f4806127d4565b6000546001600160a01b0316999097509095507f000000000000000000000000000000000000000000000000000000000000000062ffffff16945092505050565b60006107f0610f76611e7c565b60006118aa827f0000000000000000000000000000000000000000000000000000000000000000612a80565b92915050565b600080670de0b6b3a76400006001546118c7611e7c565b6118d191906131b6565b6118db91906131cd565b9050600081600654116118fa576006546118f59083613148565b6118fd565b60005b90507f00000000000000000000000000000000000000000000000000000000000000008160025461192e91906130fd565b1061193c5760009250505090565b806002547f000000000000000000000000000000000000000000000000000000000000000061196b9190613148565b6119759190613148565b9250505090565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146119c5576040516313bd2e8360e31b815260040160405180910390fd5b600554600160281b900464ffffffffff164210611a12576005546040516238ddd760e41b815264ffffffffff4281166004830152600160281b9092049190911660248201526044016107b0565b7f000000000000000000000000000000000000000000000000000000000000000082108015611a475750611a44611e7c565b82105b15611a6557604051633c80636b60e21b815260040160405180910390fd5b81600003611a8657604051633c80636b60e21b815260040160405180910390fd5b600354600003611a965760048190555b8160036000828254611aa891906130fd565b90915550505050565b6000620f4240611ae17f0000000000000000000000000000000000000000000000000000000000000000826131ef565b611af09062ffffff16846131b6565b6118aa91906131cd565b60405163aa5dd7f160e01b81523360048201526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116917f00000000000000000000000000000000000000000000000000000000000000009091169063aa5dd7f190602401602060405180830381865afa158015611b84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ba8919061303d565b6001600160a01b031614611bcf576040516313bd2e8360e31b815260040160405180910390fd5b80600260008282546112e391906130fd565b611be9612493565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b031603611c2c57610e688282610fa6565b6000611c36611e7c565b60405163a9059cbb60e01b81526001600160a01b038581166004830152602482018590529192509085169063a9059cbb906044016020604051808303816000875af1158015611c89573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cad9190613110565b50611cb6611e7c565b8114611cc157600080fd5b50505050565b60006107f0612ad6565b611cd9612493565b6001600160a01b038116611d0357604051631e4fbdf760e01b8152600060048201526024016107b0565b6111f981612924565b6000611d3f611d19612ad6565b7f0000000000000000000000000000000000000000000000000000000000000000612a80565b6006546107f091906130fd565b6000611d3f612ad6565b60008115611df35760405163a9059cbb60e01b81526001600160a01b038481166004830152602482018490527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906044016020604051808303816000875af1158015611dcd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611df19190613110565b505b6000611dfd611e7c565b90507f0000000000000000000000000000000000000000000000000000000000000000811015611e3f57611e3f6005805460ff60501b1916600160501b179055565b9392505050565b6000611e50612ad6565b9050600754811115611e625760078190555b6008805464ffffffffff19164264ffffffffff1617905590565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015610f44573d6000803e3d6000fd5b6000808260075411611ef757600754611ef9565b825b90508015611f9e5760405163375edc7760e11b81526001600160a01b038581166004830152602482018390527f00000000000000000000000000000000000000000000000000000000000000001690636ebdb8ee90604401600060405180830381600087803b158015611f6b57600080fd5b505af1158015611f7f573d6000803e3d6000fd5b50505050611f8c81612241565b611f968184613148565b9150506118aa565b509092915050565b6006546040516302dc1ca760e31b8152600481019190915262ffffff7f000000000000000000000000000000000000000000000000000000000000000016602482015260009081906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906316e0e53890604401602060405180830381865afa15801561203f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612063919061315b565b90506000816006546120759190613148565b905060008185116120865784612088565b815b9050801561223757604051633824f22960e21b81526004810182905262ffffff7f00000000000000000000000000000000000000000000000000000000000000001660248201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063e093c8a490604401602060405180830381865afa158015612123573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612147919061315b565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663315f3e7289847f00000000000000000000000000000000000000000000000000000000000000006040518463ffffffff1660e01b81526004016121bb9392919061320a565b6020604051808303816000875af11580156121da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121fe919061315b565b905061220a8383613148565b811461221857612218613132565b61222182612395565b61222b8388613148565b955050505050506118aa565b5092949350505050565b600754811115612274576007546122589082613148565b604051635795d46960e11b81526004016107b091815260200190565b6040516301ffc9a760e01b8152632464e41b60e21b60048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906301ffc9a790602401602060405180830381865afa1580156122df573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123039190613110565b1561238357604051637d0ea02d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690637d0ea02d90602401600060405180830381600087803b15801561236a57600080fd5b505af115801561237e573d6000803e3d6000fd5b505050505b80600760008282546112e39190613148565b6006548111156123ac576006546122589082613148565b604051635be980f560e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635be980f590602401600060405180830381600087803b15801561240e57600080fd5b505af1158015612422573d6000803e3d6000fd5b5050505080600660008282546112e39190613148565b6003546000901561244c57506004546118aa565b8260000361245b5750806118aa565b600083670de0b6b3a764000061246f611d0c565b61247991906131b6565b61248391906131cd565b9050828110611f9e579392505050565b6000546001600160a01b031633146107e45760405163118cdaa760e01b81523360048201526024016107b0565b60055460009064ffffffffff1642116124ec57604051631c02820f60e21b815260040160405180910390fd5b6003541561250d5760405163d26e2de960e01b815260040160405180910390fd5b60006125198484611d56565b9050611e3f81600154612b61565b6000612531611e46565b508160000361254257506000919050565b8161254d3382611ee3565b90506125593382612c01565b9050611e3f8184613148565b600354156125865760405163d26e2de960e01b815260040160405180910390fd5b60055464ffffffffff1642116125af57604051631c02820f60e21b815260040160405180910390fd5b600554600160281b900464ffffffffff1642106125fc576005546040516238ddd760e41b815264ffffffffff4281166004830152600160281b9092049190911660248201526044016107b0565b600554600160501b900460ff161561262757604051631cdde67b60e01b815260040160405180910390fd5b61262f610e87565b821115612661578161263f610e87565b604051634779077960e11b8152600481019290925260248201526044016107b0565b612669611e46565b506126937f0000000000000000000000000000000000000000000000000000000000000000612815565b604051630cfb636f60e41b8152600481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063cfb636f090602401600060405180830381600087803b1580156126f557600080fd5b505af1158015612709573d6000803e3d6000fd5b505060405163165203b760e31b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016925063b2901db8915061277d90869086907f00000000000000000000000000000000000000000000000000000000000000009060040161320a565b600060405180830381600087803b15801561279757600080fd5b505af11580156127ab573d6000803e3d6000fd5b5050505081600660008282546127c191906130fd565b92505081905550610e6881600154612b61565b60006127e08242613230565b60055490915064ffffffffff9081169082161115611540576005805464ffffffffff831664ffffffffff199091161790555050565b807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663664e97046040518163ffffffff1660e01b8152600401602060405180830381865afa158015612874573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612898919061303d565b6001600160a01b03166306a7b3766040518163ffffffff1660e01b8152600401602060405180830381865afa1580156128d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128f99190613191565b612903919061324d565b6005600b6101000a81548162ffffff021916908362ffffff16021790555050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600354156129955760405163d26e2de960e01b815260040160405180910390fd5b600554600160281b900464ffffffffff1642106129e2576005546040516238ddd760e41b815264ffffffffff4281166004830152600160281b9092049190911660248201526044016107b0565b600554600160501b900460ff1615612a0d57604051631cdde67b60e01b815260040160405180910390fd5b60055464ffffffffff164211612a3657604051631c02820f60e21b815260040160405180910390fd5b600154811115612a5157612a4c6203f4806127d4565b612a62565b612a62612a5c611e7c565b82612b61565b6111f981612a6e610e87565b600654612a7b91906130fd565b612cfd565b60008215612acd57612a9582620f42406131ef565b62ffffff166001612aa985620f42406131b6565b612ab39190613148565b612abd91906131cd565b612ac89060016130fd565b611e3f565b60009392505050565b600754600854429064ffffffffff1681118015612af557506000600654115b15612b5d57600854600090612b119064ffffffffff1683613148565b9050651cae8c13e000816005600b9054906101000a900462ffffff1662ffffff16600654612b3f91906131b6565b612b4991906131b6565b612b5391906131cd565b61197590846130fd565b5090565b60007f00000000000000000000000000000000000000000000000000000000000000008310612b905782612b93565b60005b90506000612b9f611d0c565b9050612bb3670de0b6b3a7640000826131b6565b612bbd84846131b6565b1015611cc157612bcd83836131b6565b612bdf670de0b6b3a7640000836131b6565b604051632c1f8ef160e21b8152600481019290925260248201526044016107b0565b6000808260065411612c1557600654612c17565b825b90508015611f9e576040516318af9f3960e11b81526000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063315f3e7290612c9290889086907f00000000000000000000000000000000000000000000000000000000000000009060040161320a565b6020604051808303816000875af1158015612cb1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cd5919061315b565b9050612ce082612395565b612cea8183613148565b612cf49085613148565b925050506118aa565b6000612d07611e7c565b90507f000000000000000000000000000000000000000000000000000000000000000064ffffffffff164210158015612d4c5750600154612d499060026131b6565b83115b15612d8357826001546002612d6191906131b6565b6040516387ebe85d60e01b8152600481019290925260248201526044016107b0565b612d95670de0b6b3a7640000836131b6565b612d9f82856131b6565b1115612dc3578281612db9670de0b6b3a7640000856131b6565b612d6191906131cd565b5050600155565b60008083601f840112612ddc57600080fd5b50813567ffffffffffffffff811115612df457600080fd5b602083019150836020828501011115612e0c57600080fd5b9250929050565b60008060008060408587031215612e2957600080fd5b843567ffffffffffffffff811115612e4057600080fd5b8501601f81018713612e5157600080fd5b803567ffffffffffffffff811115612e6857600080fd5b8760208260051b8401011115612e7d57600080fd5b60209182019550935085013567ffffffffffffffff811115612e9e57600080fd5b612eaa87828801612dca565b95989497509550505050565b6001600160a01b03811681146111f957600080fd5b60008060408385031215612ede57600080fd5b8235612ee981612eb6565b946020939093013593505050565b600080600060608486031215612f0c57600080fd5b8335612f1781612eb6565b95602085013595506040909401359392505050565b600060208284031215612f3e57600080fd5b5035919050565b64ffffffffff811681146111f957600080fd5b60008060408385031215612f6b57600080fd5b8235612f7681612eb6565b91506020830135612f8681612f45565b809150509250929050565b600080600060608486031215612fa657600080fd5b505081359360208301359350604090920135919050565b60008060408385031215612fd057600080fd5b50508035926020909101359150565b600080600060608486031215612ff457600080fd5b8335612fff81612eb6565b9250602084013561300f81612eb6565b929592945050506040919091013590565b60006020828403121561303257600080fd5b8135611e3f81612eb6565b60006020828403121561304f57600080fd5b8151611e3f81612eb6565b6001600160a01b0384168152604060208201819052810182905260008360608301825b858110156130ad57823561309081612eb6565b6001600160a01b031682526020928301929091019060010161307d565b509695505050505050565b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b634e487b7160e01b600052601160045260246000fd5b808201808211156118aa576118aa6130e7565b60006020828403121561312257600080fd5b81518015158114611e3f57600080fd5b634e487b7160e01b600052600160045260246000fd5b818103818111156118aa576118aa6130e7565b60006020828403121561316d57600080fd5b5051919050565b60006020828403121561318657600080fd5b8151611e3f81612f45565b6000602082840312156131a357600080fd5b815162ffffff81168114611e3f57600080fd5b80820281158282048414176118aa576118aa6130e7565b6000826131ea57634e487b7160e01b600052601260045260246000fd5b500490565b62ffffff82811682821603908111156118aa576118aa6130e7565b6001600160a01b03939093168352602083019190915262ffffff16604082015260600190565b64ffffffffff81811683821601908111156118aa576118aa6130e7565b62ffffff81811683821601908111156118aa576118aa6130e756fe9483a26ad376f30b5199a79e75df3bb05158c4ee32a348f53e83245a5e50c86ea26469706673582212209a1975e04fb13fc1ca52e414c56b5c239b9ac598c02c1ac429d1dfc9e289acd464736f6c634300081a0033a26469706673582212202f943f0c1e50fc77fe44a52efa4244454fe0fd30125d7d6aa6bf364d2f4dad7664736f6c634300081a0033","name":"PositionFactory","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/gateway/interface/IFrontendGateway.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IFrontendGateway {\n    struct FrontendCode {\n        uint256 balance;\n        address owner;\n    }\n\n    event FrontendCodeRegistered(address owner, bytes32 frontendCode);\n    event FrontendCodeTransferred(address from, address to, bytes32 frontendCode);\n    event FrontendCodeRewardsWithdrawn(address to, uint256 amount, bytes32 frontendCode);\n    event NewPositionRegistered(address position, bytes32 frontendCode);\n    event RateChangesProposed(address who, uint24 nextFeeRate, uint24 nextSavingsFeeRate, uint24 nextMintingFeeRate, uint256 nextChange);\n    event RateChangesExecuted(address who, uint24 nextFeeRate, uint24 nextSavingsFeeRate, uint24 nextMintingFeeRate);\n    \n    event InvestRewardAdded(bytes32 frontendCode, address user, uint256 amount, uint256 reward);\n    event RedeemRewardAdded(bytes32 frontendCode, address user, uint256 amount, uint256 reward);\n    event UnwrapAndSellRewardAdded(bytes32 frontendCode, address user, uint256 amount, uint256 reward);\n    event SavingsRewardAdded(bytes32 frontendCode, address saver, uint256 interest, uint256 reward);\n    event PositionRewardAdded(bytes32 frontendCode, address position, uint256 amount, uint256 reward);\n\n    error FrontendCodeAlreadyExists();\n    error NotFrontendCodeOwner();\n    error NotGatewayService();\n    error ProposedChangesToHigh();\n    error NoOpenChanges();\n    error NotDoneWaiting(uint256 minmumExecutionTime);\n    error EquityTooLow();\n\n    function invest(uint256 amount, uint256 expectedShares, bytes32 frontendCode) external returns (uint256);\n    function redeem(address target, uint256 shares, uint256 expectedProceeds, bytes32 frontendCode) external returns (uint256);\n    function unwrapAndSell(uint256 amount, bytes32 frontendCode) external returns (uint256);\n\n    function updateSavingCode(address savingsOwner, bytes32 frontendCode) external;\n    function updateSavingRewards(address saver, uint256 interest) external;\n\n    function registerPosition(address position, bytes32 frontendCode) external;\n    function updatePositionRewards(address position, uint256 amount) external;\n    function getPositionFrontendCode(address position)view external  returns(bytes32);\n\n    // Frontend Code Logic\n    function registerFrontendCode(bytes32 frontendCode) external returns (bool);\n    function transferFrontendCode(bytes32 frontendCode, address to) external returns (bool);\n    function withdrawRewards(bytes32 frontendCode) external returns (uint256);\n    function withdrawRewardsTo(bytes32 frontendCode, address to) external returns (uint256);\n\n    // Governance\n    function proposeChanges(uint24 newFeeRatePPM_, uint24 newSavingsFeeRatePPM_, uint24 newMintingFeeRatePPM_, address[] calldata helpers) external;\n    function executeChanges() external;\n}\n"},{"file_path":"contracts/gateway/interface/IMintingHubGateway.sol","source_code":"// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.10;\n\nimport {IMintingHub} from \"../../MintingHubV2/interface/IMintingHub.sol\";\nimport {IFrontendGateway} from \"./IFrontendGateway.sol\";\n\ninterface IMintingHubGateway {\n    function GATEWAY() external view returns (IFrontendGateway);\n    function notifyInterestPaid(uint256 amount) external;\n    function openPosition(address _collateralAddress, uint256 _minCollateral, uint256 _initialCollateral, uint256 _mintingMaximum, uint40 _initPeriodSeconds, uint40 _expirationSeconds, uint40 _challengeSeconds, uint24 _riskPremium, uint256 _liqPrice, uint24 _reservePPM, bytes32 _frontendCode) external returns (address);\n    function clone(address owner, address parent, uint256 _initialCollateral, uint256 _initialMint, uint40 expiration, bytes32 frontendCode) external returns (address);\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":"@openzeppelin/contracts/utils/introspection/IERC165.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Interface of the ERC-165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[ERC].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n    /**\n     * @dev Returns true if this contract implements the interface defined by\n     * `interfaceId`. See the corresponding\n     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]\n     * to learn more about how these ids are created.\n     *\n     * This function call must use less than 30 000 gas.\n     */\n    function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n"},{"file_path":"contracts/MintingHubV2/Position.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IMintingHubGateway} from \"../gateway/interface/IMintingHubGateway.sol\";\nimport {IDecentralizedEURO} from \"../interface/IDecentralizedEURO.sol\";\nimport {IReserve} from \"../interface/IReserve.sol\";\nimport {MathUtil} from \"../utils/MathUtil.sol\";\nimport {IMintingHub} from \"./interface/IMintingHub.sol\";\nimport {IPosition} from \"./interface/IPosition.sol\";\nimport {Ownable} from \"@openzeppelin/contracts/access/Ownable.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {IERC165} from \"@openzeppelin/contracts/utils/introspection/IERC165.sol\";\n\n/**\n * @title Position\n * @notice A collateralized minting position.\n */\ncontract Position is Ownable, IPosition, MathUtil {\n    /**\n     * @notice Note that this contract is intended to be cloned. All clones will share the same values for\n     * the constant and immutable fields, but have their own values for the other fields.\n     */\n\n    /**\n     * @notice The deuro price per unit of the collateral below which challenges succeed, (36 - collateral.decimals) decimals\n     */\n    uint256 public price;\n\n    /**\n     * @notice How much has been minted in total. This variable is only used in the parent position.\n     */\n    uint256 private totalMinted;\n\n    uint256 public immutable limit;\n\n    /**\n     * @notice Amount of the collateral that is currently under a challenge.\n     * Used to figure out whether there are pending challenges.\n     */\n    uint256 public challengedAmount;\n\n    /**\n     * @notice The price at which the challenge was initiated.\n     */\n    uint256 private challengedPrice;\n\n    /**\n     * @notice Challenge period in seconds.\n     */\n    uint40 public immutable challengePeriod;\n\n    /**\n     * @notice Timestamp when minting can start and the position is no longer denied.\n     */\n    uint40 public immutable start;\n\n    /**\n     * @notice End of the latest cooldown. If this is in the future, minting is suspended.\n     */\n    uint40 public cooldown;\n\n    /**\n     * @notice Timestamp of the expiration of the position. After expiration, challenges cannot be averted\n     * any more. This is also the basis for fee calculations.\n     */\n    uint40 public expiration;\n\n    bool private closed;\n\n    /**\n     * @notice The original position to help identify clones.\n     */\n    address public immutable original;\n\n    /**\n     * @notice Pointer to the minting hub.\n     */\n    address public immutable hub;\n\n    /**\n     * @notice The Eurocoin contract.\n     */\n    IDecentralizedEURO public immutable deuro;\n\n    /**\n     * @notice The collateral token.\n     */\n    IERC20 public immutable override collateral;\n\n    /**\n     * @notice Minimum acceptable collateral amount to prevent dust.\n     */\n    uint256 public immutable override minimumCollateral;\n\n    /**\n     * @notice The interest in parts per million per year that is deducted when minting dEURO.\n     */\n    uint24 public immutable riskPremiumPPM;\n\n    /**\n     * @notice The locked-in rate (including riskPremiumPPM) for this position.\n     */\n    uint24 public fixedAnnualRatePPM;\n\n    /**\n     * @notice The reserve contribution in parts per million of the minted amount.\n     */\n    uint24 public immutable reserveContribution;\n\n    /**\n     * @notice The total principal borrowed.\n     */\n    uint256 public principal;\n\n    /**\n     * @notice The total outstanding interest.\n     */\n    uint256 public interest;\n\n    /**\n     * @notice The timestamp of the last interest accrual.\n     */\n    uint40 public lastAccrual;\n\n    event MintingUpdate(uint256 collateral, uint256 price, uint256 principal);\n    event PositionDenied(address indexed sender, string message); // emitted if closed by governance\n\n    error InsufficientCollateral(uint256 needed, uint256 available);\n    error TooLate();\n    error RepaidTooMuch(uint256 excess);\n    error LimitExceeded(uint256 tried, uint256 available);\n    error ChallengeTooSmall();\n    error Expired(uint40 time, uint40 expiration);\n    error Alive();\n    error Closed();\n    error Hot();\n    error Challenged();\n    error NotHub();\n    error NotOriginal();\n    error InvalidExpiration();\n    error AlreadyInitialized();\n    error PriceTooHigh(uint256 newPrice, uint256 maxPrice);\n\n    modifier alive() {\n        if (block.timestamp >= expiration) revert Expired(uint40(block.timestamp), expiration);\n        _;\n    }\n\n    // requires that the position has always been backed by a minimal amount of collateral\n    modifier backed() {\n        if (isClosed()) revert Closed();\n        _;\n    }\n\n    modifier expired() {\n        if (block.timestamp < expiration) revert Alive();\n        _;\n    }\n\n    modifier noCooldown() {\n        if (block.timestamp <= cooldown) revert Hot();\n        _;\n    }\n\n    modifier noChallenge() {\n        if (challengedAmount > 0) revert Challenged();\n        _;\n    }\n\n    modifier onlyHub() {\n        if (msg.sender != address(hub)) revert NotHub();\n        _;\n    }\n\n    modifier ownerOrRoller() {\n        if (msg.sender != address(IMintingHub(hub).ROLLER())) _checkOwner();\n        _;\n    }\n\n    /**\n     * @dev See MintingHub.openPosition\n     *\n     * @param _riskPremiumPPM ppm of minted amount that is added to the applicable minting fee as a risk premium\n     */\n    constructor(\n        address _owner,\n        address _hub,\n        address _deuro,\n        address _collateral,\n        uint256 _minCollateral,\n        uint256 _initialLimit,\n        uint40 _initPeriod,\n        uint40 _duration,\n        uint40 _challengePeriod,\n        uint24 _riskPremiumPPM,\n        uint256 _liqPrice,\n        uint24 _reservePPM\n    ) Ownable(_owner) {\n        original = address(this);\n        hub = _hub;\n        deuro = IDecentralizedEURO(_deuro);\n        collateral = IERC20(_collateral);\n        riskPremiumPPM = _riskPremiumPPM;\n        reserveContribution = _reservePPM;\n        minimumCollateral = _minCollateral;\n        challengePeriod = _challengePeriod;\n        start = uint40(block.timestamp) + _initPeriod; // at least three days time to deny the position\n        cooldown = start;\n        expiration = start + _duration;\n        limit = _initialLimit;\n        _setPrice(_liqPrice, _initialLimit);\n        _fixRateToLeadrate(_riskPremiumPPM);\n    }\n\n    /**\n     * Initialization method for clones.\n     * Can only be called once. Should be called immediately after creating the clone.\n     */\n    function initialize(address parent, uint40 _expiration) external onlyHub {\n        if (expiration != 0) revert AlreadyInitialized();\n        if (_expiration < block.timestamp || _expiration > Position(original).expiration()) revert InvalidExpiration(); // expiration must not be later than original\n        expiration = _expiration;\n        price = Position(parent).price();\n        _fixRateToLeadrate(Position(parent).riskPremiumPPM());\n        _transferOwnership(hub);\n    }\n\n    /**\n     * Cloning a position is only allowed if the position is not challenged, not expired and not in cooldown.\n     */\n    function assertCloneable() external noChallenge noCooldown alive backed {}\n\n    /**\n     * Notify the original that some amount has been minted.\n     */\n    function notifyMint(uint256 mint_) external {\n        if (deuro.getPositionParent(msg.sender) != hub) revert NotHub();\n        totalMinted += mint_;\n    }\n\n    function notifyRepaid(uint256 repaid_) external {\n        if (deuro.getPositionParent(msg.sender) != hub) revert NotHub();\n        totalMinted -= repaid_;\n    }\n\n    /**\n     * Should only be called on the original position.\n     * Better use 'availableForMinting'.\n     */\n    function availableForClones() external view returns (uint256) {\n        // reserve capacity for the original to the extent the owner provided collateral\n        uint256 potential = (_collateralBalance() * price) / ONE_DEC18;\n        uint256 unusedPotential = principal > potential ? 0 : potential - principal;\n        if (totalMinted + unusedPotential >= limit) {\n            return 0;\n        } else {\n            return limit - totalMinted - unusedPotential;\n        }\n    }\n\n    /**\n     * The amount available for minting in this position family.\n     *\n     * Does not check if positions are challenged, closed, or under cooldown.\n     */\n    function availableForMinting() public view returns (uint256) {\n        if (address(this) == original) {\n            return limit - totalMinted;\n        } else {\n            return Position(original).availableForClones();\n        }\n    }\n\n    /**\n     * @notice Qualified pool share holders can call this method to immediately expire a freshly proposed position.\n     */\n    function deny(address[] calldata helpers, string calldata message) external {\n        if (block.timestamp >= start) revert TooLate();\n        IReserve(deuro.reserve()).checkQualified(msg.sender, helpers);\n        _close();\n        emit PositionDenied(msg.sender, message);\n    }\n\n    /**\n     * Closes the position by putting it into eternal cooldown.\n     * This allows the users to still withdraw the collateral that is left, but never to mint again.\n     */\n    function _close() internal {\n        closed = true;\n    }\n\n    function isClosed() public view returns (bool) {\n        return closed;\n    }\n\n    /**\n     * @notice This is how much the minter can actually use when minting deuro, with the rest being assigned\n     * to the minter reserve.\n     */\n    function getUsableMint(uint256 mintAmount) public view returns (uint256) {\n        return (mintAmount * (1000_000 - reserveContribution)) / 1000_000;\n    }\n\n    /**\n     * Returns the corresponding mint amount (disregarding the limit).\n     */\n    function getMintAmount(uint256 usableMint) external view returns (uint256) {\n        return _ceilDivPPM(usableMint, reserveContribution);\n    }\n\n    /**\n     * @notice \"All in one\" function to adjust the principal, the collateral amount,\n     * and the price in one transaction.\n     */\n    function adjust(uint256 newPrincipal, uint256 newCollateral, uint256 newPrice) external onlyOwner {\n        uint256 colbal = _collateralBalance();\n        if (newCollateral > colbal) {\n            collateral.transferFrom(msg.sender, address(this), newCollateral - colbal);\n        }\n        // Must be called after collateral deposit, but before withdrawal\n        if (newPrincipal < principal) {\n            uint256 debt = principal + _accrueInterest();\n            _payDownDebt(debt - newPrincipal);\n        }\n        if (newCollateral < colbal) {\n            _withdrawCollateral(msg.sender, colbal - newCollateral);\n        }\n        // Must be called after collateral withdrawal\n        if (newPrincipal > principal) {\n            _mint(msg.sender, newPrincipal - principal, newCollateral);\n        }\n        if (newPrice != price) {\n            _adjustPrice(newPrice);\n        }\n        emit MintingUpdate(newCollateral, newPrice, newPrincipal);\n    }\n\n    /**\n     * @notice Allows the position owner to adjust the liquidation price as long as there is no pending challenge.\n     * Lowering the liquidation price can be done with immediate effect, given that there is enough collateral.\n     * Increasing the liquidation price triggers a cooldown period of 3 days, during which minting is suspended.\n     */\n    function adjustPrice(uint256 newPrice) public onlyOwner {\n        _adjustPrice(newPrice);\n        emit MintingUpdate(_collateralBalance(), price, principal);\n    }\n\n    function _adjustPrice(uint256 newPrice) internal noChallenge alive backed noCooldown {\n        if (newPrice > price) {\n            _restrictMinting(3 days);\n        } else {\n            _checkCollateral(_collateralBalance(), newPrice);\n        }\n        _setPrice(newPrice, principal + availableForMinting());\n    }\n\n    function _setPrice(uint256 newPrice, uint256 bounds) internal {\n        uint256 colBalance = _collateralBalance();\n        if (block.timestamp >= start && newPrice > 2 * price) {\n            revert PriceTooHigh(newPrice, 2 * price);\n        }\n        if (newPrice * colBalance > bounds * ONE_DEC18) {\n            revert PriceTooHigh(newPrice, (bounds * ONE_DEC18) / colBalance);\n        }\n        price = newPrice;\n    }\n\n    function _collateralBalance() internal view returns (uint256) {\n        return IERC20(collateral).balanceOf(address(this));\n    }\n\n    /**\n     * @notice Mint deuro as long as there is no open challenge, the position is not subject to a cooldown,\n     * and there is sufficient collateral.\n     */\n    function mint(address target, uint256 amount) public ownerOrRoller {\n        uint256 collateralBalance = _collateralBalance();\n        _mint(target, amount, collateralBalance);\n        emit MintingUpdate(collateralBalance, price, principal);\n    }\n\n    /**\n     * @notice Returns the virtual price of the collateral in dEURO.\n     */\n    function virtualPrice() public view returns (uint256) {\n        return _virtualPrice(_collateralBalance(), price);\n    }\n\n    /**\n     * @notice Computes the virtual price of the collateral in dEURO, which is the minimum collateral\n     * price required to cover the entire debt with interest overcollateralization, lower bounded by the floor price. \n     * Returns the challenged price if a challenge is active.\n     * @param colBalance The collateral balance of the position.\n     * @param floorPrice The minimum price of the collateral in dEURO.\n     */\n    function _virtualPrice(uint256 colBalance, uint256 floorPrice) internal view returns (uint256) {\n        if (challengedAmount > 0) return challengedPrice;\n        if (colBalance == 0) return floorPrice;\n        \n        uint256 virtPrice = (_getCollateralRequirement() * ONE_DEC18) / colBalance;\n        return virtPrice < floorPrice ? floorPrice: virtPrice;\n    }\n\n    /**\n     * @notice Fixes the annual rate to the current leadrate plus the risk premium.\n     * This re-prices the entire position based on the current leadrate.\n     */\n    function _fixRateToLeadrate(uint24 _riskPremiumPPM) internal {\n        fixedAnnualRatePPM = IMintingHub(hub).RATE().currentRatePPM() + _riskPremiumPPM;\n    }\n\n    /**\n     * @notice Accrues interest on the principal amount since the last accrual time.\n     * @return newInterest The total outstanding interest to be paid.\n     */\n    function _accrueInterest() internal returns (uint256 newInterest) {\n        newInterest = _calculateInterest();\n\n        if (newInterest > interest) {\n            interest = newInterest;\n        }\n\n        lastAccrual = uint40(block.timestamp);\n    }\n\n    /**\n     * @notice Computes the total outstanding interest, including newly accrued interest.\n     * @dev This function calculates interest accumulated since the last accrual based on\n     * the principal amount, the annual interest rate, and the elapsed time.\n     * The newly accrued interest is added to the current outstanding interest.\n     * @return newInterest The total outstanding interest, including newly accrued interest.\n     */\n    function _calculateInterest() internal view returns (uint256 newInterest) {\n        uint256 timestamp = block.timestamp;\n        newInterest = interest;\n\n        if (timestamp > lastAccrual && principal > 0) {\n            uint256 delta = timestamp - lastAccrual;\n            newInterest += (principal * fixedAnnualRatePPM * delta) / (365 days * 1_000_000);\n        }\n\n        return newInterest;\n    }\n\n    /**\n     * @notice Calculates the current debt (principal + accrued interest)\n     * @return Total debt without interest overcollateralization\n     */\n    function _getDebt() internal view returns (uint256) {\n        return principal + _calculateInterest();\n    }\n\n    /**\n     * @notice Calculates total debt accounting for interest overcollateralization\n     * @return Total debt including overcollateralized interest\n     */\n    function _getCollateralRequirement() internal view returns (uint256) {\n        return principal + _ceilDivPPM(_calculateInterest(), reserveContribution);\n    }\n\n    /**\n     * @notice Public function to calculate current debt\n     * @return The total current debt (principal + current accrued interest)\n     */\n    function getDebt() public view returns (uint256) {\n        return _getDebt();\n    }\n    \n    /**\n     * @notice Public function to calculate current debt with overcollateralized interest\n     * @return The total debt including overcollateralized interest\n     */\n    function getCollateralRequirement() public view returns (uint256) {\n        return _getCollateralRequirement();\n    }\n\n    /**\n     * @notice Public function to get the current outstanding interest\n     */\n    function getInterest() public view returns (uint256) {\n        return _calculateInterest();\n    }\n\n    function _mint(address target, uint256 amount, uint256 collateral_) internal noChallenge noCooldown alive backed {\n        if (amount > availableForMinting()) revert LimitExceeded(amount, availableForMinting());\n\n        _accrueInterest(); // accrue interest\n        _fixRateToLeadrate(riskPremiumPPM); // sync interest rate with leadrate\n\n        Position(original).notifyMint(amount);\n        deuro.mintWithReserve(target, amount, reserveContribution);\n\n        principal += amount;\n        _checkCollateral(collateral_, price);\n    }\n\n    function _restrictMinting(uint40 period) internal {\n        uint40 horizon = uint40(block.timestamp) + period;\n        if (horizon > cooldown) {\n            cooldown = horizon;\n        }\n    }\n\n    /**\n     * @notice Repays a specified amount of debt from `msg.sender`, prioritizing accrued interest first and then principal.\n     * @dev This method integrates the logic of paying accrued interest before principal, as introduced in the continuous\n     *      interest accrual model. Any interest repaid is collected as profit, and principal repayment uses `burnFromWithReserve`.\n     *\n     *      Unlike previous implementations, this function delegates the actual repayment steps to `_payDownDebt`, ensuring\n     *      a clean separation of logic. As a result:\n     *      - Any surplus `amount` beyond what is needed to pay all outstanding interest and principal is never withdrawn\n     *        from `msg.sender`’s account (no leftover handling required).\n     *      - The function can be called while there are challenges, though in that scenario, collateral withdrawals remain\n     *        blocked until all challenges are resolved.\n     *\n     *      To fully close the position (bring `debt` to 0), the amount required generally follows the formula:\n     *      `debt = principal + interest`. Under normal conditions, this simplifies to:\n     *      `amount = (principal * (1000000 - reservePPM)) / 1000000 + interest`.\n     *\n     *      For example, if `principal` is 40, `interest` is 10, and `reservePPM` is 200000, repaying 42 dEURO\n     *      is required to fully close the position.\n     *\n     * @param amount The maximum amount of dEURO that `msg.sender` is willing to repay.\n     * @return used  The actual amount of dEURO used for interest and principal repayment.\n     *\n     * Emits a {MintingUpdate} event.\n     */\n    function repay(uint256 amount) public returns (uint256) {\n        uint256 used = _payDownDebt(amount);\n        emit MintingUpdate(_collateralBalance(), price, principal);\n        return used;\n    }\n\n    function repayFull() external returns (uint256) {\n        return repay(principal + _accrueInterest());\n    }\n\n    /**\n     * @notice Updates oustanding principal and notifies the original position that a portion of the total\n     * minted has been repaid.\n     */\n    function _notifyRepaid(uint256 amount) internal {\n        if (amount > principal) revert RepaidTooMuch(amount - principal);\n        Position(original).notifyRepaid(amount);\n        principal -= amount;\n    }\n\n    /**\n     * @notice Updates outstanding interest and notifies the minting hub gateway that interest has been paid.\n     */\n    function _notifyInterestPaid(uint256 amount) internal {\n        if (amount > interest) revert RepaidTooMuch(amount - interest);\n        if (IERC165(hub).supportsInterface(type(IMintingHubGateway).interfaceId)) {\n            IMintingHubGateway(hub).notifyInterestPaid(amount);\n        }\n        interest -= amount;\n    }\n\n    /**\n     * @notice Forcefully sells some of the collateral after the position has expired, using the given buyer as the source of proceeds.\n     * @dev\n     * - Can only be called by the minting hub once the position is expired.\n     * - Requires that there are no open challenges, ensuring that a forced sale is not used to circumvent the challenge process.\n     * - The proceeds from the sale are first used to repay any accrued interest (treated as profit, collected via `collectProfits`),\n     *   and then the principal (via `burnFromWithReserve`). This ensures correct accounting, where interest is always realized as profit before principal is returned.\n     * - If all debt is fully repaid and there are surplus proceeds, these are transferred to the position owner.\n     * - If there is a shortfall (not enough proceeds to fully repay the debt) and no remaining collateral, the system covers the loss.\n     *\n     * Do not allow a forced sale as long as there is an open challenge. Otherwise, a forced sale by the owner\n     * himself could remove any incentive to launch challenges shortly before the expiration. (CS-ZCHF2-001)\n     *\n     * @param buyer         The address buying the collateral. This address provides `proceeds` in dEURO to repay the outstanding debt.\n     * @param colAmount     The amount of collateral to be forcibly sold and transferred to the `buyer`.\n     * @param proceeds      The amount of dEURO proceeds provided by the `buyer` to repay the outstanding debt.\n     *\n     * Emits a {MintingUpdate} event indicating the updated collateral balance, price, and debt after the forced sale.\n     */\n    function forceSale(address buyer, uint256 colAmount, uint256 proceeds) external onlyHub expired noChallenge {\n        uint256 debt = principal + _accrueInterest();\n        uint256 remainingCollateral = _sendCollateral(buyer, colAmount); // Send collateral to buyer\n\n        // No debt, everything goes to owner if proceeds > 0\n        if (debt == 0) {\n            if (proceeds > 0) {\n                deuro.transferFrom(buyer, owner(), proceeds);\n            }\n            emit MintingUpdate(_collateralBalance(), price, principal);\n            return;\n        }\n\n        // Note: A postcondition of _repayPrincipalNet is `principal + interest > 0 => proceeds == 0` (see assert below).\n        proceeds = _repayInterest(buyer, proceeds);\n        proceeds = _repayPrincipalNet(buyer, proceeds);\n\n        // If remaining collateral is 0 and `principal + interest` > 0, cover the shortfall with the system.\n        if (remainingCollateral == 0 && principal + interest > 0) {\n            assert(proceeds == 0);\n            deuro.coverLoss(address(this), principal + interest);\n            if (interest > 0) {\n                deuro.collectProfits(address(this), interest);\n                _notifyInterestPaid(interest);\n            }\n            deuro.burnWithoutReserve(principal, reserveContribution);\n            _notifyRepaid(principal);\n        } else if (proceeds > 0) {\n            // All debt paid, leftover proceeds is profit for owner\n            deuro.transferFrom(buyer, owner(), proceeds);\n        }\n\n        emit MintingUpdate(_collateralBalance(), price, principal);\n    }\n\n    /**\n     * @notice Withdraw any ERC20 token that might have ended up on this address.\n     * Withdrawing collateral is subject to the same restrictions as withdrawCollateral(...).\n     */\n    function withdraw(address token, address target, uint256 amount) external onlyOwner {\n        if (token == address(collateral)) {\n            withdrawCollateral(target, amount);\n        } else {\n            uint256 balance = _collateralBalance();\n            IERC20(token).transfer(target, amount);\n            require(balance == _collateralBalance()); // guard against double-entry-point tokens\n        }\n    }\n\n    /**\n     * @notice Withdraw collateral from the position up to the extent that it is still well collateralized afterwards.\n     * Not possible as long as there is an open challenge or the contract is subject to a cooldown.\n     *\n     * Withdrawing collateral below the minimum collateral amount formally closes the position.\n     */\n    function withdrawCollateral(address target, uint256 amount) public ownerOrRoller {\n        uint256 balance = _withdrawCollateral(target, amount);\n        emit MintingUpdate(balance, price, principal);\n    }\n\n    function _withdrawCollateral(address target, uint256 amount) internal noCooldown noChallenge returns (uint256) {\n        uint256 balance = _sendCollateral(target, amount);\n        _checkCollateral(balance, price);\n        return balance;\n    }\n\n    /**\n     * @notice Transfer the challenged collateral to the bidder. Only callable by minting hub.\n     */\n    function transferChallengedCollateral(address target, uint256 amount) external onlyHub {\n        uint256 newBalance = _sendCollateral(target, amount);\n        emit MintingUpdate(newBalance, price, principal);\n    }\n\n    function _sendCollateral(address target, uint256 amount) internal returns (uint256) {\n        // Some weird tokens fail when trying to transfer 0 amounts\n        if (amount > 0) {\n            IERC20(collateral).transfer(target, amount);\n        }\n        uint256 balance = _collateralBalance();\n        if (balance < minimumCollateral) {\n            _close();\n        }\n        return balance;\n    }\n\n    /**\n     * @notice This invariant must always hold and must always be checked when any of the three\n     * variables change in an adverse way. Ensures that the position overcollateralizes interest\n     * by the same percentage as the reserve contribution.\n     */\n    function _checkCollateral(uint256 collateralReserve, uint256 atPrice) internal view {\n        uint256 relevantCollateral = collateralReserve < minimumCollateral ? 0 : collateralReserve;\n        uint256 collateralRequirement = _getCollateralRequirement();\n        \n        if (relevantCollateral * atPrice < collateralRequirement * ONE_DEC18) {\n            revert InsufficientCollateral(relevantCollateral * atPrice, collateralRequirement * ONE_DEC18);\n        }\n    }\n\n    /**\n     * @notice Repays a specified amount of debt from `msg.sender`, prioritizing accrued interest first and then principal.\n     * @return The actual amount of dEURO used for interest and principal repayment.\n     */\n    function _payDownDebt(uint256 amount) internal returns (uint256) {\n        _accrueInterest();\n        if (amount == 0) return 0;\n\n        uint256 remaining = amount;\n        remaining = _repayInterest(msg.sender, remaining); // Repay interest\n        remaining = _repayPrincipal(msg.sender, remaining); // Repay principal\n\n        return amount - remaining;\n    }\n\n    /**\n     * @notice Repays a specified amount of interest from `msg.sender`.\n     * @dev Assumes that _accrueInterest has been called before this function.\n     * @return `amount` remaining after interest repayment.\n     */\n    function _repayInterest(address payer, uint256 amount) internal returns (uint256) {\n        uint256 repayment = (interest > amount) ? amount : interest;\n        if (repayment > 0) {\n            deuro.collectProfits(payer, repayment);\n            _notifyInterestPaid(repayment);\n            return amount - repayment;\n        }\n        return amount;\n    }\n\n    /**\n     * @notice Repays a specified amount of principal from `msg.sender`.\n     * @param payer The address of the entity repaying the debt.\n     * @param amount The repayment amount, including the reserve portion.\n     * @return amount remaining after principal repayment\n     */\n    function _repayPrincipal(address payer, uint256 amount) internal returns (uint256) {\n        uint256 repayment = (principal > amount) ? amount : principal;\n        if (repayment > 0) {\n            uint256 returnedReserve = deuro.burnFromWithReserve(payer, repayment, reserveContribution);\n            _notifyRepaid(repayment);\n            return amount - (repayment - returnedReserve);\n        }\n        return amount;\n    }\n\n    /**\n     * @notice Repays principal from `payer` using the net repayment amount (excluding reserves).\n     * To repay an exact amount including reserves, use `_repayPrincipal(address payer, uint256 amount)`.\n     *\n     * @param payer The address of the entity repaying the debt.\n     * @param amount The repayment amount, excluding the reserve portion, i.e. the net amount.\n     * @return amount remaining after principal repayment.\n     */\n    function _repayPrincipalNet(address payer, uint256 amount) internal returns (uint256) {\n        uint256 availableReserve = deuro.calculateAssignedReserve(principal, reserveContribution);\n        uint256 maxRepayment = principal - availableReserve;\n        uint256 repayment = amount > maxRepayment ? maxRepayment : amount;\n        if (repayment > 0) {\n            uint256 freedAmount = deuro.calculateFreedAmount(repayment, reserveContribution);\n            uint256 returnedReserve = deuro.burnFromWithReserve(payer, freedAmount, reserveContribution);\n            assert(returnedReserve == freedAmount - repayment);\n            _notifyRepaid(freedAmount);\n            return amount - repayment;\n        }\n        return amount;\n    }\n\n    /**\n     * @notice Returns the liquidation price and the durations for phase1 and phase2 of the challenge.\n     * Both phases are usually of equal duration, but near expiration, phase one is adjusted such that\n     * it cannot last beyond the expiration date of the position.\n     */\n    function challengeData() external view returns (uint256 liqPrice, uint40 phase) {\n        return (_virtualPrice(_collateralBalance(), price), challengePeriod);\n    }\n\n    function notifyChallengeStarted(uint256 size, uint256 _price) external onlyHub alive {\n        // Require minimum size. Collateral balance can be below minimum if it was partially challenged before.\n        if (size < minimumCollateral && size < _collateralBalance()) revert ChallengeTooSmall();\n        if (size == 0) revert ChallengeTooSmall();\n\n        if (challengedAmount == 0) challengedPrice = _price;\n        challengedAmount += size;\n    }\n\n    /**\n     * @param size amount of collateral challenged (dec18)\n     */\n    function notifyChallengeAverted(uint256 size) external onlyHub {\n        challengedAmount -= size;\n\n        // Don't allow minter to close the position immediately so challenge can be repeated before\n        // the owner has a chance to mint more on an undercollateralized position\n        _restrictMinting(1 days);\n    }\n\n    /**\n     * @notice Notifies the position that a challenge was successful.\n     * Everything else is assumed to be handled by the hub.\n     *\n     * @param _size amount of the collateral bid for\n     * @return (position owner, effective challenge size in deuro, amount of principal to repay, amount of interest to pay, reserve ppm)\n     */\n    function notifyChallengeSucceeded(\n        uint256 _size\n    ) external onlyHub returns (address, uint256, uint256, uint256, uint32) {\n        _accrueInterest();\n\n        challengedAmount -= _size;\n        uint256 colBal = _collateralBalance();\n        if (colBal < _size) {\n            _size = colBal;\n        }\n\n        // Determine how much of the debt must be repaid based on challenged collateral\n        uint256 interestToPay = (colBal == 0) ? 0 : (interest * _size) / colBal;\n        uint256 principalToPay = (colBal == 0) ? 0 : (principal * _size) / colBal;\n        _notifyInterestPaid(interestToPay);\n        _notifyRepaid(principalToPay);\n\n        // Give time for additional challenges before the owner can mint again.\n        _restrictMinting(3 days);\n\n        return (owner(), _size, principalToPay, interestToPay, reserveContribution);\n    }\n}\n"},{"file_path":"contracts/MintingHubV2/PositionRoller.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IDecentralizedEURO} from \"../interface/IDecentralizedEURO.sol\";\nimport {IERC165} from \"@openzeppelin/contracts/utils/introspection/IERC165.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {IMintingHubGateway} from \"../gateway/interface/IMintingHubGateway.sol\";\nimport {IMintingHub} from \"./interface/IMintingHub.sol\";\nimport {IPosition} from \"./interface/IPosition.sol\";\nimport {IReserve} from \"../interface/IReserve.sol\";\nimport {Ownable} from \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title PositionRoller\n *\n * Helper to roll over a debt from an old position to a new one.\n * Both positions should have the same collateral. Otherwise, it does not make much sense.\n */\ncontract PositionRoller {\n    IDecentralizedEURO private deuro;\n\n    error NotOwner(address pos);\n    error NotPosition(address pos);\n    error Log(uint256, uint256, uint256);\n\n    event Roll(address source, uint256 collWithdraw, uint256 repay, address target, uint256 collDeposit, uint256 mint);\n\n    constructor(address deuro_) {\n        deuro = IDecentralizedEURO(deuro_);\n    }\n\n    /**\n     * Convenience method to roll an old position into a new one.\n     *\n     * Pre-condition: an allowance for the roller to spend the collateral asset on behalf of the caller,\n     * i.e., one should set collateral.approve(roller, collateral.balanceOf(sourcePosition)).\n     *\n     * The following is assumed:\n     * - If the limit of the target position permits, the user wants to roll everything.\n     * - The user does not want to add additional collateral, but excess collateral is returned.\n     * - If not enough can be minted in the new position, it is acceptable for the roller to use dEURO from the msg.sender.\n     */\n    function rollFully(IPosition source, IPosition target) external {\n        rollFullyWithExpiration(source, target, target.expiration());\n    }\n\n    /**\n     * Like rollFully, but with a custom expiration date for the new position.\n     */\n    function rollFullyWithExpiration(IPosition source, IPosition target, uint40 expiration) public {\n        require(source.collateral() == target.collateral());\n        uint256 principal = source.principal();\n        uint256 interest = source.getInterest();\n        uint256 usableMint = source.getUsableMint(principal) + interest; // Roll interest into principal\n        uint256 mintAmount = target.getMintAmount(usableMint);\n        uint256 collateralToWithdraw = IERC20(source.collateral()).balanceOf(address(source));\n        uint256 targetPrice = target.price();\n        uint256 depositAmount = (mintAmount * 10 ** 18 + targetPrice - 1) / targetPrice; // round up\n        if (depositAmount > collateralToWithdraw) {\n            // If we need more collateral than available from the old position, we opt for taking\n            // the missing funds from the caller instead of requiring additional collateral.\n            depositAmount = collateralToWithdraw;\n            mintAmount = (depositAmount * target.price()) / 10 ** 18; // round down, rest will be taken from caller\n        }\n\n        roll(source, principal + interest, collateralToWithdraw, target, mintAmount, depositAmount, expiration);\n    }\n\n    /**\n     * Rolls the source position into the target position using a flash loan.\n     * Both the source and the target position must recognize this roller.\n     * It is the responsibility of the caller to ensure that both positions are valid contracts.\n     *\n     * @param source The source position, must be owned by the msg.sender.\n     * @param repay The amount of principal to repay from the source position using a flash loan, freeing up some or all collateral .\n     * @param collWithdraw Collateral to move from the source position to the msg.sender.\n     * @param target The target position. If not owned by msg.sender or if it does not have the desired expiration,\n     *               it is cloned to create a position owned by the msg.sender.\n     * @param mint The amount to be minted from the target position using collateral from msg.sender.\n     * @param collDeposit The amount of collateral to be sent from msg.sender to the target position.\n     * @param expiration The desired expiration date for the target position.\n     */\n    function roll(\n        IPosition source,\n        uint256 repay,\n        uint256 collWithdraw,\n        IPosition target,\n        uint256 mint,\n        uint256 collDeposit,\n        uint40 expiration\n    ) public valid(source) valid(target) own(source) {\n        deuro.mint(address(this), repay); // take a flash loan\n        uint256 used = source.repay(repay);\n        source.withdrawCollateral(msg.sender, collWithdraw);\n        if (mint > 0) {\n            IERC20 targetCollateral = IERC20(target.collateral());\n            if (Ownable(address(target)).owner() != msg.sender || expiration != target.expiration()) {\n                targetCollateral.transferFrom(msg.sender, address(this), collDeposit); // get the new collateral\n                targetCollateral.approve(target.hub(), collDeposit); // approve the new collateral and clone:\n                target = _cloneTargetPosition(target, source, collDeposit, mint, expiration);\n            } else {\n                // We can roll into the provided existing position.\n                // We do not verify whether the target position was created by the known minting hub in order\n                // to allow positions to be rolled into future versions of the minting hub.\n                targetCollateral.transferFrom(msg.sender, address(target), collDeposit);\n                target.mint(msg.sender, mint);\n            }\n        }\n\n        // Transfer remaining flash loan to caller for repayment\n        if (repay > used) {\n            deuro.transfer(msg.sender, repay - used);\n        }\n\n        deuro.burnFrom(msg.sender, repay); // repay the flash loan\n        emit Roll(address(source), collWithdraw, repay, address(target), collDeposit, mint);\n    }\n\n    /**\n     * Clones the target position and mints the specified amount using the given collateral.\n     */\n    function _cloneTargetPosition (\n        IPosition target,\n        IPosition source,\n        uint256 collDeposit,\n        uint256 mint,\n        uint40 expiration\n    ) internal returns (IPosition) {\n        if (IERC165(target.hub()).supportsInterface(type(IMintingHubGateway).interfaceId)) {\n            bytes32 frontendCode = IMintingHubGateway(target.hub()).GATEWAY().getPositionFrontendCode(\n                address(source)\n            );\n            return IPosition(\n                IMintingHubGateway(target.hub()).clone(\n                    msg.sender,\n                    address(target),\n                    collDeposit,\n                    mint,\n                    expiration,\n                    frontendCode // use the same frontend code\n                )\n            );\n        } else {\n            return IPosition(\n                IMintingHub(target.hub()).clone(msg.sender, address(target), collDeposit, mint, expiration)\n            );\n        }\n    }\n\n    modifier own(IPosition pos) {\n        if (Ownable(address(pos)).owner() != msg.sender) revert NotOwner(address(pos));\n        _;\n    }\n\n    modifier valid(IPosition pos) {\n        if (deuro.getPositionParent(address(pos)) == address(0x0)) revert NotPosition(address(pos));\n        _;\n    }\n}\n"},{"file_path":"contracts/MintingHubV2/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    function RATE() external view returns (ILeadrate);\n\n    function ROLLER() external view returns (PositionRoller);\n\n    function challenge(\n        address _positionAddr,\n        uint256 _collateralAmount,\n        uint256 minimumPrice\n    ) external returns (uint256);\n\n    function bid(uint32 _challengeNumber, uint256 size, bool postponeCollateralReturn) external;\n\n    function returnPostponedCollateral(address collateral, address target) external;\n\n    function buyExpiredCollateral(IPosition pos, uint256 upToAmount) external returns (uint256);\n\n    function clone(address owner, address parent, uint256 _initialCollateral, uint256 _initialMint, uint40 expiration) external returns (address);\n}\n"},{"file_path":"contracts/MintingHubV2/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);\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 newMinted, uint256 newCollateral, uint256 newPrice) external;\n\n    function adjustPrice(uint256 newPrice) external;\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 withdraw(address token, address target, uint256 amount) external;\n\n    function withdrawCollateral(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/IDecentralizedEURO.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IReserve} from \"./IReserve.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\ninterface IDecentralizedEURO is IERC20 {\n    function suggestMinter(\n        address _minter,\n        uint256 _applicationPeriod,\n        uint256 _applicationFee,\n        string calldata _message\n    ) external;\n\n    function registerPosition(address position) external;\n\n    function denyMinter(address minter, address[] calldata helpers, string calldata message) external;\n\n    function reserve() external view returns (IReserve);\n\n    function minterReserve() external view returns (uint256);\n\n    function calculateAssignedReserve(uint256 mintedAmount, uint32 _reservePPM) external view returns (uint256);\n\n    function calculateFreedAmount(uint256 amountExcludingReserve, uint32 _reservePPM) external view returns (uint256);\n\n    function equity() external view returns (uint256);\n\n    function isMinter(address minter) external view returns (bool);\n\n    function getPositionParent(address position) external view returns (address);\n\n    function mint(address target, uint256 amount) external;\n\n    function mintWithReserve(address target, uint256 amount, uint32 reservePPM) external;\n\n    function burn(uint256 amount) external;\n\n    function burnFrom(address target, uint256 amount) external;\n\n    function burnWithoutReserve(uint256 amount, uint32 reservePPM) external;\n\n    function burnFromWithReserve(\n        address payer,\n        uint256 targetTotalBurnAmount,\n        uint32 reservePPM\n    ) external returns (uint256);\n\n    function coverLoss(address source, uint256 amount) external;\n\n    function distributeProfits(address recipient, uint256 amount) external;\n\n    function collectProfits(address source, uint256 _amount) external;\n}\n"},{"file_path":"contracts/interface/ILeadrate.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface ILeadrate {\n   function currentRatePPM() external view returns (uint24);\n   function currentTicks() external view returns (uint64);\n}"},{"file_path":"contracts/interface/IReserve.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\ninterface IReserve is IERC20 {\n    function invest(uint256 amount, uint256 expected) external returns (uint256);\n    function checkQualified(address sender, address[] calldata helpers) external view;\n}\n"},{"file_path":"contracts/utils/MathUtil.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\n/**\n * @title Functions for share valuation\n */\ncontract MathUtil {\n    uint256 internal constant ONE_DEC18 = 10 ** 18;\n\n    // Let's go for 12 digits of precision (18-6)\n    uint256 internal constant THRESH_DEC18 = 10 ** 6;\n\n    /**\n     * @notice Fifth root with Halley approximation\n     *         Number 1e18 decimal\n     * @param _v     number for which we calculate x**(1/5)\n     * @return returns _v**(1/5)\n     */\n    function _fifthRoot(uint256 _v) internal pure returns (uint256) {\n        // Good first guess for _v slightly above 1.0, which is often the case in the dEURO system\n        uint256 x = _v > ONE_DEC18 && _v < 10 ** 19 ? (_v - ONE_DEC18) / 5 + ONE_DEC18 : ONE_DEC18;\n        uint256 diff;\n        do {\n            uint256 powX5 = _power5(x);\n            uint256 xnew = (x * (2 * powX5 + 3 * _v)) / (3 * powX5 + 2 * _v);\n            diff = xnew > x ? xnew - x : x - xnew;\n            x = xnew;\n        } while (diff > THRESH_DEC18);\n        return x;\n    }\n\n    function _mulD18(uint256 _a, uint256 _b) internal pure returns (uint256) {\n        return (_a * _b) / ONE_DEC18;\n    }\n\n    function _divD18(uint256 _a, uint256 _b) internal pure returns (uint256) {\n        return (_a * ONE_DEC18) / _b;\n    }\n\n    function _power5(uint256 _x) internal pure returns (uint256) {\n        return _mulD18(_mulD18(_mulD18(_mulD18(_x, _x), _x), _x), _x);\n    }\n\n    function _min(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a < b ? a : b;\n    }\n    \n    /**\n     * @notice Performs ceiling division for PPM calculations using formula: ceil(amount / (1 - ppm/1000000))\n     * @param amount The base amount to divide\n     * @param ppm Parts per million value (e.g., 200000 for 20%)\n     * @return The result of ceiling division\n     */\n    function _ceilDivPPM(uint256 amount, uint24 ppm) internal pure returns (uint256) {\n        return amount == 0 ? 0 : (amount * 1_000_000 - 1) / (1_000_000 - ppm) + 1;\n    }\n}\n"}],"certified":false,"conflicting_implementations":null,"abi":[{"inputs":[{"internalType":"address","name":"_parent","type":"address"}],"name":"clonePosition","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_deuro","type":"address"},{"internalType":"address","name":"_collateral","type":"address"},{"internalType":"uint256","name":"_minCollateral","type":"uint256"},{"internalType":"uint256","name":"_initialLimit","type":"uint256"},{"internalType":"uint40","name":"_initPeriod","type":"uint40"},{"internalType":"uint40","name":"_duration","type":"uint40"},{"internalType":"uint40","name":"_challengePeriod","type":"uint40"},{"internalType":"uint24","name":"_riskPremiumPPM","type":"uint24"},{"internalType":"uint256","name":"_liqPrice","type":"uint256"},{"internalType":"uint24","name":"_reserve","type":"uint24"}],"name":"createNewPosition","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"}],"is_changed_bytecode":false,"is_partially_verified":false,"constructor_args":null}