{"file_path":"contracts/MintingHubV3/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(payable(_parent));\n        parent.assertCloneable();\n        Position clone = Position(payable(_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":"0x608060405234801561001057600080fd5b50600436106100365760003560e01c80635d824f761461003b578063b3e891801461006a575b600080fd5b61004e61004936600461029e565b61007d565b6040516001600160a01b03909116815260200160405180910390f35b61004e61007836600461035b565b6100d9565b60008b338c8c8c8c8c8c8c8c8c8c6040516100979061024c565b6100ac9c9b9a9998979695949392919061037f565b604051809103906000f0801580156100c8573d6000803e3d6000fd5b509c9b505050505050505050505050565b600080829050806001600160a01b0316630e49d77e6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561011a57600080fd5b505af115801561012e573d6000803e3d6000fd5b50505050600061019e826001600160a01b03166346c715fa6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610175573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610199919061040f565b6101a6565b949350505050565b6000808260601b9050604051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b81528160148201526e5af43d82803e903d91602b57fd5bf360881b60288201526037816000f09250506001600160a01b0382166102465760405162461bcd60e51b8152602060048201526016602482015275115490cc4c4d8dce8818dc99585d194819985a5b195960521b604482015260640160405180910390fd5b50919050565b614a348061042d83390190565b6001600160a01b038116811461026e57600080fd5b50565b803564ffffffffff8116811461028657600080fd5b919050565b803562ffffff8116811461028657600080fd5b60008060008060008060008060008060006101608c8e0312156102c057600080fd5b8b356102cb81610259565b9a5060208c01356102db81610259565b995060408c01356102eb81610259565b985060608c0135975060808c0135965061030760a08d01610271565b955061031560c08d01610271565b945061032360e08d01610271565b93506103326101008d0161028b565b92506101208c013591506103496101408d0161028b565b90509295989b509295989b9093969950565b60006020828403121561036d57600080fd5b813561037881610259565b9392505050565b6001600160a01b038d811682528c811660208301528b811660408301528a1660608201526080810189905260a0810188905264ffffffffff87811660c0830152861660e0820152610180810164ffffffffff861661010083015262ffffff8516610120830152836101408301526103fe61016083018462ffffff169052565b9d9c50505050505050505050505050565b60006020828403121561042157600080fd5b81516103788161025956fe6101c060405234801561001157600080fd5b50604051614a34380380614a34833981016040819052610030916103d8565b8b6001600160a01b03811661006057604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b6100698161012f565b503060e0526001600160a01b038b8116610100528a81166101205289166101405262ffffff8084166101805281166101a05261016088905264ffffffffff841660a0526100b686426104c2565b64ffffffffff1660c08190526005805464ffffffffff1916821790556100dd9086906104c2565b6005805464ffffffffff92909216650100000000000264ffffffffff60281b199092169190911790556080879052610115828861017f565b61011e8361022e565b505050505050505050505050610591565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000610189610320565b905060c05164ffffffffff1642101580156101b057506001546101ad9060026104e5565b83115b156101e7578260015460026101c591906104e5565b6040516387ebe85d60e01b815260048101929092526024820152604401610057565b6101f9670de0b6b3a7640000836104e5565b61020382856104e5565b111561022757828161021d670de0b6b3a7640000856104e5565b6101c591906104fc565b5050600155565b80610100516001600160a01b031663664e97046040518163ffffffff1660e01b8152600401602060405180830381865afa158015610270573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610294919061051e565b6001600160a01b03166306a7b3766040518163ffffffff1660e01b8152600401602060405180830381865afa1580156102d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102f59190610542565b6102ff919061055d565b6005600b6101000a81548162ffffff021916908362ffffff16021790555050565b610140516040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa15801561036a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061038e9190610578565b905090565b6001600160a01b03811681146103a857600080fd5b50565b805164ffffffffff811681146103c057600080fd5b919050565b805162ffffff811681146103c057600080fd5b6000806000806000806000806000806000806101808d8f0312156103fb57600080fd5b8c5161040681610393565b60208e0151909c5061041781610393565b60408e0151909b5061042881610393565b60608e0151909a5061043981610393565b60808e015160a08f0151919a509850965061045660c08e016103ab565b955061046460e08e016103ab565b94506104736101008e016103ab565b93506104826101208e016103c5565b6101408e0151909350915061049a6101608e016103c5565b90509295989b509295989b509295989b565b634e487b7160e01b600052601160045260246000fd5b64ffffffffff81811683821601908111156104df576104df6104ac565b92915050565b80820281158282048414176104df576104df6104ac565b60008261051957634e487b7160e01b600052601260045260246000fd5b500490565b60006020828403121561053057600080fd5b815161053b81610393565b9392505050565b60006020828403121561055457600080fd5b61053b826103c5565b62ffffff81811683821601908111156104df576104df6104ac565b60006020828403121561058a57600080fd5b5051919050565b60805160a05160c05160e05161010051610120516101405161016051610180516101a05161423e6107f66000396000818161068a015281816111d801528181611a9101528181611ad201528181611d1f0152818161293501528181612dc601528181612eac01528181612f8001528181613422015281816138370152613b2d015260008181610809015261333c015260008181610a0d01528181611c7701528181612b4c015281816139ee0152613a28015260008181610313015281816103c50152818161040d01528181610aea01528181611e4e01528181612070015281816126e60152818161272e015281816127bf01528181612acf01528181612c9601526139060152600081816108d101528181610d3401528181610f63015281816110840152818161114b015281816111ff0152818161127b0152818161164901528181611d9e01528181611fd201528181612d2901528181612dfa01528181612ed601528181612f4f015281816133ef0152613afc01526000818161033a0152818161061e01528181610e3101528181610e9c015281816113f6015281816114bd015281816115a30152818161162501528181611702015281816119280152818161199101528181611bea01528181611d7a01528181611fae0152818161265b01528181612a3001528181612bdf01526134e5015260008181610740015281816112e10152818161133601528181611780015281816130b50152613376015260008181610a4101528181610ced0152613bce015260008181610b9601526113cf01526000818161098e0152818161131001528181611b640152611ba5015261423e6000f3fe6080604052600436106103035760003560e01c8063787a08a611610190578063babe7c74116100dc578063d8dfeb4511610095578063f2fde38b1161006f578063f2fde38b14610b41578063f37c2ecf14610b61578063f3f480d914610b84578063fcb4555b14610bb857600080fd5b8063d8dfeb4514610ad8578063e5711e8b14610b0c578063e5a4bed314610b2c57600080fd5b8063babe7c74146109fb578063be9a655514610a2f578063c2b6b58c14610a63578063c392f76614610a82578063c54a89ca14610a98578063cfb636f014610ab857600080fd5b80639de2f79611610149578063a4d66daf11610123578063a4d66daf1461097c578063a8a3e31d146109b0578063b8e2426c146109c5578063ba5d3078146109e557600080fd5b80639de2f796146109265780639e9a1a5f14610946578063a035b1fe1461096657600080fd5b8063787a08a61461082b5780637b3baab4146108495780637ccd4f711461086757806382b8eaf5146108bf5780638da5cb5b146108f35780638ea875f31461091157600080fd5b8063365a86fc1161024f57806346c715fa116102085780636d4749fa116101e25780636d4749fa146107a2578063715018a6146107c257806372bf079e146107d7578063730d48b7146107f757600080fd5b806346c715fa1461072e57806349746f10146107625780635be980f51461078257600080fd5b8063365a86fc1461060c578063371fd8e6146106585780633a7c29fb1461067857806340c10f19146106c057806342c3994f146106e05780634665096d146106f357600080fd5b80631dbcff26116102bc57806329d93d671161029657806329d93d67146105925780632a37eeae146105a7578063329864aa146105bc578063350c35e9146105ec57600080fd5b80631dbcff261461053c578063211d79831461055c57806324e657fe1461057c57600080fd5b806306177fea146104875780630e49d77e146104bc57806311ed0e77146104d157806313a06782146104e457806314a6bf0f146105075780631bbea34c1461051c57600080fd5b3661048257336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610480577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663ad5c46486040518163ffffffff1660e01b8152600401602060405180830381865afa158015610396573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103ba9190613ca2565b6001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03161461040b57604051631a38687560e21b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561046657600080fd5b505af115801561047a573d6000803e3d6000fd5b50505050505b005b600080fd5b34801561049357600080fd5b506104a76104a2366004613cbf565b610bd8565b60405190151581526020015b60405180910390f35b3480156104c857600080fd5b50610480610bed565b6104806104df366004613cf9565b610cb6565b3480156104f057600080fd5b506104f9610cd2565b6040519081526020016104b3565b34801561051357600080fd5b506104f9610ce1565b34801561052857600080fd5b50610480610537366004613d83565b610ceb565b34801561054857600080fd5b50610480610557366004613cbf565b610e26565b34801561056857600080fd5b50610480610577366004613e26565b610e91565b34801561058857600080fd5b506104f960035481565b34801561059e57600080fd5b506104f96112bb565b3480156105b357600080fd5b506104f96112d5565b3480156105c857600080fd5b506105d16113b6565b6040805192835264ffffffffff9091166020830152016104b3565b3480156105f857600080fd5b50610480610607366004613cbf565b6113f4565b34801561061857600080fd5b506106407f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016104b3565b34801561066457600080fd5b506104f9610673366004613e5b565b6114a2565b34801561068457600080fd5b506106ac7f000000000000000000000000000000000000000000000000000000000000000081565b60405162ffffff90911681526020016104b3565b3480156106cc57600080fd5b506104806106db366004613cbf565b6114bb565b6104806106ee366004613e74565b611583565b3480156106ff57600080fd5b5060055461071890600160281b900464ffffffffff1681565b60405164ffffffffff90911681526020016104b3565b34801561073a57600080fd5b506106407f000000000000000000000000000000000000000000000000000000000000000081565b34801561076e57600080fd5b5061048061077d366004613e5b565b611598565b34801561078e57600080fd5b5061048061079d366004613e5b565b611608565b3480156107ae57600080fd5b506104806107bd366004613edd565b6116f7565b3480156107ce57600080fd5b50610480611950565b3480156107e357600080fd5b506104806107f2366004613e5b565b611962565b34801561080357600080fd5b506106ac7f000000000000000000000000000000000000000000000000000000000000000081565b34801561083757600080fd5b506005546107189064ffffffffff1681565b34801561085557600080fd5b506008546107189064ffffffffff1681565b34801561087357600080fd5b50610887610882366004613e5b565b611980565b604080516001600160a01b039096168652602086019490945292840191909152606083015263ffffffff16608082015260a0016104b3565b3480156108cb57600080fd5b506106407f000000000000000000000000000000000000000000000000000000000000000081565b3480156108ff57600080fd5b506000546001600160a01b0316610640565b34801561091d57600080fd5b506104f9611abd565b34801561093257600080fd5b506104f9610941366004613e5b565b611aca565b34801561095257600080fd5b50610480610961366004613f16565b611af6565b34801561097257600080fd5b506104f960015481565b34801561098857600080fd5b506104f97f000000000000000000000000000000000000000000000000000000000000000081565b3480156109bc57600080fd5b506104f9611b13565b3480156109d157600080fd5b506104806109e0366004613f3b565b611bdf565b3480156109f157600080fd5b506104f960065481565b348015610a0757600080fd5b506104f97f000000000000000000000000000000000000000000000000000000000000000081565b348015610a3b57600080fd5b506107187f000000000000000000000000000000000000000000000000000000000000000081565b348015610a6f57600080fd5b50600554600160501b900460ff166104a7565b348015610a8e57600080fd5b506104f960075481565b348015610aa457600080fd5b506104f9610ab3366004613e5b565b611d14565b348015610ac457600080fd5b50610480610ad3366004613e5b565b611d5d565b348015610ae457600080fd5b506106407f000000000000000000000000000000000000000000000000000000000000000081565b348015610b1857600080fd5b50610480610b27366004613f5d565b611e44565b348015610b3857600080fd5b506104f9611f33565b348015610b4d57600080fd5b50610480610b5c366004613f9e565b611f3d565b348015610b6d57600080fd5b506005546106ac90600160581b900462ffffff1681565b348015610b9057600080fd5b506107187f000000000000000000000000000000000000000000000000000000000000000081565b348015610bc457600080fd5b50610480610bd3366004613cbf565b611f78565b6000610be48383611f8c565b90505b92915050565b60035415610c0e5760405163d26e2de960e01b815260040160405180910390fd5b60055464ffffffffff164211610c3757604051631c02820f60e21b815260040160405180910390fd5b600554600160281b900464ffffffffff164210610c89576005546040516238ddd760e41b815264ffffffffff4281166004830152600160281b9092049190911660248201526044015b60405180910390fd5b600554600160501b900460ff1615610cb457604051631cdde67b60e01b815260040160405180910390fd5b565b610cbe612626565b610ccc848484600085612653565b50505050565b6000610cdc612926565b905090565b6000610cdc612966565b7f000000000000000000000000000000000000000000000000000000000000000064ffffffffff164210610d325760405163ecdd1c2960e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663cd3293de6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d90573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610db49190613ca2565b6001600160a01b031663352e3a833386866040518463ffffffff1660e01b8152600401610de393929190613fbb565b60006040518083038186803b158015610dfb57600080fd5b505afa158015610e0f573d6000803e3d6000fd5b50505050610e1b612970565b610ccc338383612985565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610e6f576040516313bd2e8360e31b815260040160405180910390fd5b6000610e7b8383612aa1565b9050610e8c81600154600654612b7a565b505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610eda576040516313bd2e8360e31b815260040160405180910390fd5b600554600160281b900464ffffffffff16421015610f0b576040516302de694d60e41b815260040160405180910390fd5b60035415610f2c5760405163d26e2de960e01b815260040160405180910390fd5b6000610f36612c48565b600654610f43919061402f565b90506000610f518585612aa1565b90508160000361103a57821561101d577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166323b872dd86610fa36000546001600160a01b031690565b6040516001600160e01b031960e085901b1681526001600160a01b03928316600482015291166024820152604481018690526064016020604051808303816000875af1158015610ff7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061101b9190614042565b505b611033611028612c7e565b600154600654612b7a565b5050505050565b6110448584612ce5565b92506110508584612da8565b92508015801561106f5750600060075460065461106d919061402f565b115b156112735782156110825761108261405f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d1fa5e98306007546006546110c2919061402f565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b15801561110857600080fd5b505af115801561111c573d6000803e3d6000fd5b50505050600060075411156111ba5760075460405163375edc7760e11b815230600482015260248101919091527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636ebdb8ee90604401600060405180830381600087803b15801561119757600080fd5b505af11580156111ab573d6000803e3d6000fd5b505050506111ba600754613043565b6006546040516363b20c3360e11b8152600481019190915262ffffff7f00000000000000000000000000000000000000000000000000000000000000001660248201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063c764186690604401600060405180830381600087803b15801561124b57600080fd5b505af115801561125f573d6000803e3d6000fd5b5050505061126e600654613088565b61101d565b821561101d577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166323b872dd86610fa36000546001600160a01b031690565b6000610cdc6112c8612c48565b600654610673919061402f565b60006001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361133457600254610cdc907f0000000000000000000000000000000000000000000000000000000000000000614075565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a8a3e31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611392573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cdc9190614088565b6000806113cc6113c4612c7e565b60015461312b565b927f000000000000000000000000000000000000000000000000000000000000000092509050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663f09e9e3a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611452573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114769190613ca2565b6001600160a01b0316336001600160a01b03161461149657611496612626565b6000610e7b8383613186565b6000806114ae836131ed565b9050610be7611028612c7e565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663f09e9e3a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611519573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061153d9190613ca2565b6001600160a01b0316336001600160a01b03161461155d5761155d612626565b6000611567612c7e565b9050611574838383613232565b610e8c81600154600654612b7a565b61158b612626565b6110338585858585612653565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146115e1576040516313bd2e8360e31b815260040160405180910390fd5b80600360008282546115f39190614075565b909155506116059050620151806134a1565b50565b60405163aa5dd7f160e01b81523360048201526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116917f00000000000000000000000000000000000000000000000000000000000000009091169063aa5dd7f190602401602060405180830381865afa158015611692573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116b69190613ca2565b6001600160a01b0316146116dd576040516313bd2e8360e31b815260040160405180910390fd5b80600260008282546116ef9190614075565b909155505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611740576040516313bd2e8360e31b815260040160405180910390fd5b600554600160281b900464ffffffffff161561176e5760405162dc149f60e41b815260040160405180910390fd5b428164ffffffffff16108061181157507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316634665096d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156117dc573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061180091906140a1565b64ffffffffff168164ffffffffff16115b1561182f57604051637d9533a960e11b815260040160405180910390fd5b806005806101000a81548164ffffffffff021916908364ffffffffff160217905550816001600160a01b031663a035b1fe6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561188f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118b39190614088565b600181905550611923826001600160a01b031663730d48b76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156118fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061191e91906140be565b6134e2565b61194c7f00000000000000000000000000000000000000000000000000000000000000006135f1565b5050565b611958612626565b610cb460006135f1565b61196a612626565b611975816000613641565b611605611028612c7e565b600080808080336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146119cf576040516313bd2e8360e31b815260040160405180910390fd5b6119d7612c48565b5085600360008282546119ea9190614075565b90915550600090506119fa612c7e565b905086811015611a08578096505b60008115611a2e578188600754611a1f91906140e3565b611a2991906140fa565b611a31565b60005b905060008215611a59578289600654611a4a91906140e3565b611a5491906140fa565b611a5c565b60005b9050611a6782613043565b611a7081613088565b611a7c6203f4806134a1565b6000546001600160a01b0316999097509095507f000000000000000000000000000000000000000000000000000000000000000062ffffff16945092505050565b6000610cdc6113c4612c7e565b6000610be7827f0000000000000000000000000000000000000000000000000000000000000000613782565b611afe612626565b611b088282613641565b61194c611028612c7e565b600080670de0b6b3a7640000600154611b2a612c7e565b611b3491906140e3565b611b3e91906140fa565b905060008160065411611b5d57600654611b589083614075565b611b60565b60005b90507f000000000000000000000000000000000000000000000000000000000000000081600254611b91919061402f565b10611b9f5760009250505090565b806002547f0000000000000000000000000000000000000000000000000000000000000000611bce9190614075565b611bd89190614075565b9250505090565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611c28576040516313bd2e8360e31b815260040160405180910390fd5b600554600160281b900464ffffffffff164210611c75576005546040516238ddd760e41b815264ffffffffff4281166004830152600160281b909204919091166024820152604401610c80565b7f000000000000000000000000000000000000000000000000000000000000000082108015611caa5750611ca7612c7e565b82105b15611cc857604051633c80636b60e21b815260040160405180910390fd5b81600003611ce957604051633c80636b60e21b815260040160405180910390fd5b600354600003611cf95760048190555b8160036000828254611d0b919061402f565b90915550505050565b6000620f4240611d447f00000000000000000000000000000000000000000000000000000000000000008261411c565b611d539062ffffff16846140e3565b610be791906140fa565b60405163aa5dd7f160e01b81523360048201526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116917f00000000000000000000000000000000000000000000000000000000000000009091169063aa5dd7f190602401602060405180830381865afa158015611de7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e0b9190613ca2565b6001600160a01b031614611e32576040516313bd2e8360e31b815260040160405180910390fd5b80600260008282546116ef919061402f565b611e4c612626565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b031603611e9e57604051632e28519560e01b815260040160405180910390fd5b6000611ea8612c7e565b60405163a9059cbb60e01b81526001600160a01b038581166004830152602482018590529192509085169063a9059cbb906044016020604051808303816000875af1158015611efb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f1f9190614042565b50611f28612c7e565b8114610ccc57600080fd5b6000610cdc6137d8565b611f45612626565b6001600160a01b038116611f6f57604051631e4fbdf760e01b815260006004820152602401610c80565b611605816135f1565b611f80612626565b6000610e7b838361389d565b60405163aa5dd7f160e01b81526001600160a01b0383811660048301526000917f00000000000000000000000000000000000000000000000000000000000000008216917f0000000000000000000000000000000000000000000000000000000000000000169063aa5dd7f190602401602060405180830381865afa158015612019573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061203d9190613ca2565b6001600160a01b03161461205357506000610be7565b82306001600160a01b0382160361206e576000915050610be7565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b031663d8dfeb456040518163ffffffff1660e01b8152600401602060405180830381865afa1580156120d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120fa9190613ca2565b6001600160a01b031614612112576000915050610be7565b806001600160a01b031663787a08a66040518163ffffffff1660e01b8152600401602060405180830381865afa158015612150573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061217491906140a1565b64ffffffffff16421161218b576000915050610be7565b806001600160a01b0316634665096d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156121c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121ed91906140a1565b64ffffffffff164210612204576000915050610be7565b6000816001600160a01b03166324e657fe6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612244573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122689190614088565b1115612278576000915050610be7565b806001600160a01b031663c2b6b58c6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156122b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122da9190614042565b156122e9576000915050610be7565b806001600160a01b031663a035b1fe6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612327573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061234b9190614088565b83111561235c576000915050610be7565b806001600160a01b031663ba5d30786040518163ffffffff1660e01b8152600401602060405180830381865afa15801561239a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123be9190614088565b6000036123cf576000915050610be7565b683635c9adc5dea00000816001600160a01b031663ba5d30786040518163ffffffff1660e01b8152600401602060405180830381865afa158015612417573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061243b9190614088565b101561244b576000915050610be7565b42816001600160a01b031663f3f480d96040518163ffffffff1660e01b8152600401602060405180830381865afa15801561248a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124ae91906140a1565b826001600160a01b031663787a08a66040518163ffffffff1660e01b8152600401602060405180830381865afa1580156124ec573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061251091906140a1565b61251a9190614137565b64ffffffffff161115612531576000915050610be7565b806001600160a01b031663f3f480d96040518163ffffffff1660e01b8152600401602060405180830381865afa15801561256f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061259391906140a1565b6125a49064ffffffffff164261402f565b816001600160a01b0316634665096d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156125e2573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061260691906140a1565b64ffffffffff161161261c576000915050610be7565b5060019392505050565b6000546001600160a01b03163314610cb45760405163118cdaa760e01b8152336004820152602401610c80565b34156127a1577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663ad5c46486040518163ffffffff1660e01b8152600401602060405180830381865afa1580156126b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126db9190613ca2565b6001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03161461272c57604051631a38687560e21b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561278757600080fd5b505af115801561279b573d6000803e3d6000fd5b50505050505b60006127ab612c7e565b90508085111561286a576001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166323b872dd33306127f0858a614075565b6040516001600160e01b031960e086901b1681526001600160a01b03938416600482015292909116602483015260448201526064016020604051808303816000875af1158015612844573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128689190614042565b505b6006548610156128a257600061287e612c48565b60065461288b919061402f565b905061289f61289a8883614075565b6131ed565b50505b808510156128de5781156128c9576128c3336128be8784614075565b61389d565b506128de565b6128dc336128d78784614075565b613186565b505b6006548611156129005761290033600654886128fa9190614075565b87613232565b6001548414612913576129138484613641565b61291e858588612b7a565b505050505050565b60006129596129336137d8565b7f0000000000000000000000000000000000000000000000000000000000000000613782565b600654610cdc919061402f565b60006129596137d8565b6005805460ff60501b1916600160501b179055565b8060008190036129a85760405163017636cb60e71b815260040160405180910390fd5b6101f48111156129d6576040516368f2ea7760e01b8152600481018290526101f46024820152604401610c80565b836001600160a01b03167faca80c800ec0d2aa9d9d31b7f886a1dd3067d4676abc637626a18ffb9381653d8484604051612a1192919061417d565b60405180910390a260405163f32ddc2d60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063f32ddc2d90612a6990879087908790600401614199565b600060405180830381600087803b158015612a8357600080fd5b505af1158015612a97573d6000803e3d6000fd5b5050505050505050565b60008115612b3e5760405163a9059cbb60e01b81526001600160a01b038481166004830152602482018490527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906044016020604051808303816000875af1158015612b18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b3c9190614042565b505b6000612b48612c7e565b90507f0000000000000000000000000000000000000000000000000000000000000000811015610be457610be4612970565b60408051848152602081018490529081018290527f9483a26ad376f30b5199a79e75df3bb05158c4ee32a348f53e83245a5e50c86e9060600160405180910390a160405163d6d87bdb60e01b81526004810184905260248101839052604481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063d6d87bdb90606401600060405180830381600087803b158015612c2b57600080fd5b505af1158015612c3f573d6000803e3d6000fd5b50505050505050565b6000612c526137d8565b9050600754811115612c645760078190555b6008805464ffffffffff19164264ffffffffff1617905590565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015611392573d6000803e3d6000fd5b6000808260075411612cf957600754612cfb565b825b90508015612da05760405163375edc7760e11b81526001600160a01b038581166004830152602482018390527f00000000000000000000000000000000000000000000000000000000000000001690636ebdb8ee90604401600060405180830381600087803b158015612d6d57600080fd5b505af1158015612d81573d6000803e3d6000fd5b50505050612d8e81613043565b612d988184614075565b915050610be7565b509092915050565b6006546040516302dc1ca760e31b8152600481019190915262ffffff7f000000000000000000000000000000000000000000000000000000000000000016602482015260009081906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906316e0e53890604401602060405180830381865afa158015612e41573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e659190614088565b9050600081600654612e779190614075565b90506000818511612e885784612e8a565b815b9050801561303957604051633824f22960e21b81526004810182905262ffffff7f00000000000000000000000000000000000000000000000000000000000000001660248201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063e093c8a490604401602060405180830381865afa158015612f25573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f499190614088565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663315f3e7289847f00000000000000000000000000000000000000000000000000000000000000006040518463ffffffff1660e01b8152600401612fbd939291906141c7565b6020604051808303816000875af1158015612fdc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130009190614088565b905061300c8383614075565b811461301a5761301a61405f565b61302382613088565b61302d8388614075565b95505050505050610be7565b5092949350505050565b6007548111156130765760075461305a9082614075565b604051635795d46960e11b8152600401610c8091815260200190565b80600760008282546116ef9190614075565b60065481111561309f5760065461305a9082614075565b604051635be980f560e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635be980f590602401600060405180830381600087803b15801561310157600080fd5b505af1158015613115573d6000803e3d6000fd5b5050505080600660008282546116ef9190614075565b6003546000901561313f5750600454610be7565b8260000361314e575080610be7565b600083670de0b6b3a7640000613162612926565b61316c91906140e3565b61317691906140fa565b9050828110612da0579392505050565b60055460009064ffffffffff1642116131b257604051631c02820f60e21b815260040160405180910390fd5b600354156131d35760405163d26e2de960e01b815260040160405180910390fd5b60006131df8484612aa1565b9050610be481600154613a24565b60006131f7612c48565b508160000361320857506000919050565b816132133382612ce5565b905061321f3382613ac4565b905061322b8184614075565b9392505050565b600354156132535760405163d26e2de960e01b815260040160405180910390fd5b60055464ffffffffff16421161327c57604051631c02820f60e21b815260040160405180910390fd5b600554600160281b900464ffffffffff1642106132c9576005546040516238ddd760e41b815264ffffffffff4281166004830152600160281b909204919091166024820152604401610c80565b600554600160501b900460ff16156132f457604051631cdde67b60e01b815260040160405180910390fd5b6132fc6112d5565b82111561332e578161330c6112d5565b604051634779077960e11b815260048101929092526024820152604401610c80565b613336612c48565b506133607f00000000000000000000000000000000000000000000000000000000000000006134e2565b604051630cfb636f60e41b8152600481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063cfb636f090602401600060405180830381600087803b1580156133c257600080fd5b505af11580156133d6573d6000803e3d6000fd5b505060405163165203b760e31b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016925063b2901db8915061344a90869086907f0000000000000000000000000000000000000000000000000000000000000000906004016141c7565b600060405180830381600087803b15801561346457600080fd5b505af1158015613478573d6000803e3d6000fd5b50505050816006600082825461348e919061402f565b92505081905550610e8c81600154613a24565b60006134ad8242614137565b60055490915064ffffffffff908116908216111561194c576005805464ffffffffff831664ffffffffff199091161790555050565b807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663664e97046040518163ffffffff1660e01b8152600401602060405180830381865afa158015613541573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135659190613ca2565b6001600160a01b03166306a7b3766040518163ffffffff1660e01b8152600401602060405180830381865afa1580156135a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135c691906140be565b6135d091906141ed565b6005600b6101000a81548162ffffff021916908362ffffff16021790555050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600354156136625760405163d26e2de960e01b815260040160405180910390fd5b600554600160281b900464ffffffffff1642106136af576005546040516238ddd760e41b815264ffffffffff4281166004830152600160281b909204919091166024820152604401610c80565b600554600160501b900460ff16156136da57604051631cdde67b60e01b815260040160405180910390fd5b6001548211156137535760055464ffffffffff16421161370d57604051631c02820f60e21b815260040160405180910390fd5b6001600160a01b03811661372c576137276203f4806134a1565b613764565b6137368183611f8c565b61372757604051635d8903cd60e11b815260040160405180910390fd5b61376461375e612c7e565b83613a24565b61194c826137706112d5565b60065461377d919061402f565b613bc0565b600082156137cf5761379782620f424061411c565b62ffffff1660016137ab85620f42406140e3565b6137b59190614075565b6137bf91906140fa565b6137ca90600161402f565b610be4565b50600092915050565b600754600854429064ffffffffff16811180156137f757506000600654115b15613899576008546000906138139064ffffffffff1683614075565b6005549091506801b5a660ea44b80000908290600160581b900462ffffff1661385f7f0000000000000000000000000000000000000000000000000000000000000000620f424061411c565b62ffffff1660065461387191906140e3565b61387b91906140e3565b61388591906140e3565b61388f91906140fa565b611bd8908461402f565b5090565b60055460009064ffffffffff1642116138c957604051631c02820f60e21b815260040160405180910390fd5b600354156138ea5760405163d26e2de960e01b815260040160405180910390fd5b81156139e057604051632e1a7d4d60e01b8152600481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561395257600080fd5b505af1158015613966573d6000803e3d6000fd5b505050506000836001600160a01b03168360405160006040518083038185875af1925050503d80600081146139b7576040519150601f19603f3d011682016040523d82523d6000602084013e6139bc565b606091505b50509050806139de57604051633d2cec6f60e21b815260040160405180910390fd5b505b60006139ea612c7e565b90507f0000000000000000000000000000000000000000000000000000000000000000811015613a1c57613a1c612970565b610be4816001545b60007f00000000000000000000000000000000000000000000000000000000000000008310613a535782613a56565b60005b90506000613a62612926565b9050613a76670de0b6b3a7640000826140e3565b613a8084846140e3565b1015610ccc57613a9083836140e3565b613aa2670de0b6b3a7640000836140e3565b604051632c1f8ef160e21b815260048101929092526024820152604401610c80565b6000808260065411613ad857600654613ada565b825b90508015612da0576040516318af9f3960e11b81526000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063315f3e7290613b5590889086907f0000000000000000000000000000000000000000000000000000000000000000906004016141c7565b6020604051808303816000875af1158015613b74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b989190614088565b9050613ba382613088565b613bad8183614075565b613bb79085614075565b92505050610be7565b6000613bca612c7e565b90507f000000000000000000000000000000000000000000000000000000000000000064ffffffffff164210158015613c0f5750600154613c0c9060026140e3565b83115b15613c4657826001546002613c2491906140e3565b6040516387ebe85d60e01b815260048101929092526024820152604401610c80565b613c58670de0b6b3a7640000836140e3565b613c6282856140e3565b1115613c86578281613c7c670de0b6b3a7640000856140e3565b613c2491906140fa565b5050600155565b6001600160a01b038116811461160557600080fd5b600060208284031215613cb457600080fd5b8151610be481613c8d565b60008060408385031215613cd257600080fd5b8235613cdd81613c8d565b946020939093013593505050565b801515811461160557600080fd5b60008060008060808587031215613d0f57600080fd5b8435935060208501359250604085013591506060850135613d2f81613ceb565b939692955090935050565b60008083601f840112613d4c57600080fd5b50813567ffffffffffffffff811115613d6457600080fd5b602083019150836020828501011115613d7c57600080fd5b9250929050565b60008060008060408587031215613d9957600080fd5b843567ffffffffffffffff811115613db057600080fd5b8501601f81018713613dc157600080fd5b803567ffffffffffffffff811115613dd857600080fd5b8760208260051b8401011115613ded57600080fd5b60209182019550935085013567ffffffffffffffff811115613e0e57600080fd5b613e1a87828801613d3a565b95989497509550505050565b600080600060608486031215613e3b57600080fd5b8335613e4681613c8d565b95602085013595506040909401359392505050565b600060208284031215613e6d57600080fd5b5035919050565b600080600080600060a08688031215613e8c57600080fd5b8535945060208601359350604086013592506060860135613eac81613c8d565b91506080860135613ebc81613ceb565b809150509295509295909350565b64ffffffffff8116811461160557600080fd5b60008060408385031215613ef057600080fd5b8235613efb81613c8d565b91506020830135613f0b81613eca565b809150509250929050565b60008060408385031215613f2957600080fd5b823591506020830135613f0b81613c8d565b60008060408385031215613f4e57600080fd5b50508035926020909101359150565b600080600060608486031215613f7257600080fd5b8335613f7d81613c8d565b92506020840135613f8d81613c8d565b929592945050506040919091013590565b600060208284031215613fb057600080fd5b8135610be481613c8d565b6001600160a01b0384168152604060208201819052810182905260008360608301825b8581101561400e578235613ff181613c8d565b6001600160a01b0316825260209283019290910190600101613fde565b509695505050505050565b634e487b7160e01b600052601160045260246000fd5b80820180821115610be757610be7614019565b60006020828403121561405457600080fd5b8151610be481613ceb565b634e487b7160e01b600052600160045260246000fd5b81810381811115610be757610be7614019565b60006020828403121561409a57600080fd5b5051919050565b6000602082840312156140b357600080fd5b8151610be481613eca565b6000602082840312156140d057600080fd5b815162ffffff81168114610be457600080fd5b8082028115828204841417610be757610be7614019565b60008261411757634e487b7160e01b600052601260045260246000fd5b500490565b62ffffff8281168282160390811115610be757610be7614019565b64ffffffffff8181168382160190811115610be757610be7614019565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b602081526000614191602083018486614154565b949350505050565b6001600160a01b03841681526040602082018190526000906141be9083018486614154565b95945050505050565b6001600160a01b03939093168352602083019190915262ffffff16604082015260600190565b62ffffff8181168382160190811115610be757610be761401956fea2646970667358221220eb9d5898312a137d8f4911ff30ce09bd7944d020bf79bde95617bcb43b192e5c64736f6c634300081a0033a264697066735822122004263ed2656985c139e0e8ead84db8a1b5737e3a1a4ce347a17a9be94061524e64736f6c634300081a0033","optimization_enabled":true,"verified_twin_address_hash":null,"is_verified":true,"compiler_settings":{"evmVersion":"paris","libraries":{},"metadata":{"bytecodeHash":"ipfs","useLiteralContent":true},"optimizer":{"enabled":true,"runs":200},"outputSelection":{"*":{"":["*"],"*":["*"]}}},"optimization_runs":200,"sourcify_repo_url":null,"decoded_constructor_args":null,"compiler_version":"v0.8.26+commit.8a97fa7a","is_verified_via_verifier_alliance":false,"verified_at":"2026-03-23T16:07:46.725569Z","implementations":[],"proxy_type":null,"external_libraries":[],"creation_bytecode":"0x6080604052348015600f57600080fd5b50614e968061001f6000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80635d824f761461003b578063b3e891801461006a575b600080fd5b61004e61004936600461029e565b61007d565b6040516001600160a01b03909116815260200160405180910390f35b61004e61007836600461035b565b6100d9565b60008b338c8c8c8c8c8c8c8c8c8c6040516100979061024c565b6100ac9c9b9a9998979695949392919061037f565b604051809103906000f0801580156100c8573d6000803e3d6000fd5b509c9b505050505050505050505050565b600080829050806001600160a01b0316630e49d77e6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561011a57600080fd5b505af115801561012e573d6000803e3d6000fd5b50505050600061019e826001600160a01b03166346c715fa6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610175573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610199919061040f565b6101a6565b949350505050565b6000808260601b9050604051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b81528160148201526e5af43d82803e903d91602b57fd5bf360881b60288201526037816000f09250506001600160a01b0382166102465760405162461bcd60e51b8152602060048201526016602482015275115490cc4c4d8dce8818dc99585d194819985a5b195960521b604482015260640160405180910390fd5b50919050565b614a348061042d83390190565b6001600160a01b038116811461026e57600080fd5b50565b803564ffffffffff8116811461028657600080fd5b919050565b803562ffffff8116811461028657600080fd5b60008060008060008060008060008060006101608c8e0312156102c057600080fd5b8b356102cb81610259565b9a5060208c01356102db81610259565b995060408c01356102eb81610259565b985060608c0135975060808c0135965061030760a08d01610271565b955061031560c08d01610271565b945061032360e08d01610271565b93506103326101008d0161028b565b92506101208c013591506103496101408d0161028b565b90509295989b509295989b9093969950565b60006020828403121561036d57600080fd5b813561037881610259565b9392505050565b6001600160a01b038d811682528c811660208301528b811660408301528a1660608201526080810189905260a0810188905264ffffffffff87811660c0830152861660e0820152610180810164ffffffffff861661010083015262ffffff8516610120830152836101408301526103fe61016083018462ffffff169052565b9d9c50505050505050505050505050565b60006020828403121561042157600080fd5b81516103788161025956fe6101c060405234801561001157600080fd5b50604051614a34380380614a34833981016040819052610030916103d8565b8b6001600160a01b03811661006057604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b6100698161012f565b503060e0526001600160a01b038b8116610100528a81166101205289166101405262ffffff8084166101805281166101a05261016088905264ffffffffff841660a0526100b686426104c2565b64ffffffffff1660c08190526005805464ffffffffff1916821790556100dd9086906104c2565b6005805464ffffffffff92909216650100000000000264ffffffffff60281b199092169190911790556080879052610115828861017f565b61011e8361022e565b505050505050505050505050610591565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000610189610320565b905060c05164ffffffffff1642101580156101b057506001546101ad9060026104e5565b83115b156101e7578260015460026101c591906104e5565b6040516387ebe85d60e01b815260048101929092526024820152604401610057565b6101f9670de0b6b3a7640000836104e5565b61020382856104e5565b111561022757828161021d670de0b6b3a7640000856104e5565b6101c591906104fc565b5050600155565b80610100516001600160a01b031663664e97046040518163ffffffff1660e01b8152600401602060405180830381865afa158015610270573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610294919061051e565b6001600160a01b03166306a7b3766040518163ffffffff1660e01b8152600401602060405180830381865afa1580156102d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102f59190610542565b6102ff919061055d565b6005600b6101000a81548162ffffff021916908362ffffff16021790555050565b610140516040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa15801561036a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061038e9190610578565b905090565b6001600160a01b03811681146103a857600080fd5b50565b805164ffffffffff811681146103c057600080fd5b919050565b805162ffffff811681146103c057600080fd5b6000806000806000806000806000806000806101808d8f0312156103fb57600080fd5b8c5161040681610393565b60208e0151909c5061041781610393565b60408e0151909b5061042881610393565b60608e0151909a5061043981610393565b60808e015160a08f0151919a509850965061045660c08e016103ab565b955061046460e08e016103ab565b94506104736101008e016103ab565b93506104826101208e016103c5565b6101408e0151909350915061049a6101608e016103c5565b90509295989b509295989b509295989b565b634e487b7160e01b600052601160045260246000fd5b64ffffffffff81811683821601908111156104df576104df6104ac565b92915050565b80820281158282048414176104df576104df6104ac565b60008261051957634e487b7160e01b600052601260045260246000fd5b500490565b60006020828403121561053057600080fd5b815161053b81610393565b9392505050565b60006020828403121561055457600080fd5b61053b826103c5565b62ffffff81811683821601908111156104df576104df6104ac565b60006020828403121561058a57600080fd5b5051919050565b60805160a05160c05160e05161010051610120516101405161016051610180516101a05161423e6107f66000396000818161068a015281816111d801528181611a9101528181611ad201528181611d1f0152818161293501528181612dc601528181612eac01528181612f8001528181613422015281816138370152613b2d015260008181610809015261333c015260008181610a0d01528181611c7701528181612b4c015281816139ee0152613a28015260008181610313015281816103c50152818161040d01528181610aea01528181611e4e01528181612070015281816126e60152818161272e015281816127bf01528181612acf01528181612c9601526139060152600081816108d101528181610d3401528181610f63015281816110840152818161114b015281816111ff0152818161127b0152818161164901528181611d9e01528181611fd201528181612d2901528181612dfa01528181612ed601528181612f4f015281816133ef0152613afc01526000818161033a0152818161061e01528181610e3101528181610e9c015281816113f6015281816114bd015281816115a30152818161162501528181611702015281816119280152818161199101528181611bea01528181611d7a01528181611fae0152818161265b01528181612a3001528181612bdf01526134e5015260008181610740015281816112e10152818161133601528181611780015281816130b50152613376015260008181610a4101528181610ced0152613bce015260008181610b9601526113cf01526000818161098e0152818161131001528181611b640152611ba5015261423e6000f3fe6080604052600436106103035760003560e01c8063787a08a611610190578063babe7c74116100dc578063d8dfeb4511610095578063f2fde38b1161006f578063f2fde38b14610b41578063f37c2ecf14610b61578063f3f480d914610b84578063fcb4555b14610bb857600080fd5b8063d8dfeb4514610ad8578063e5711e8b14610b0c578063e5a4bed314610b2c57600080fd5b8063babe7c74146109fb578063be9a655514610a2f578063c2b6b58c14610a63578063c392f76614610a82578063c54a89ca14610a98578063cfb636f014610ab857600080fd5b80639de2f79611610149578063a4d66daf11610123578063a4d66daf1461097c578063a8a3e31d146109b0578063b8e2426c146109c5578063ba5d3078146109e557600080fd5b80639de2f796146109265780639e9a1a5f14610946578063a035b1fe1461096657600080fd5b8063787a08a61461082b5780637b3baab4146108495780637ccd4f711461086757806382b8eaf5146108bf5780638da5cb5b146108f35780638ea875f31461091157600080fd5b8063365a86fc1161024f57806346c715fa116102085780636d4749fa116101e25780636d4749fa146107a2578063715018a6146107c257806372bf079e146107d7578063730d48b7146107f757600080fd5b806346c715fa1461072e57806349746f10146107625780635be980f51461078257600080fd5b8063365a86fc1461060c578063371fd8e6146106585780633a7c29fb1461067857806340c10f19146106c057806342c3994f146106e05780634665096d146106f357600080fd5b80631dbcff26116102bc57806329d93d671161029657806329d93d67146105925780632a37eeae146105a7578063329864aa146105bc578063350c35e9146105ec57600080fd5b80631dbcff261461053c578063211d79831461055c57806324e657fe1461057c57600080fd5b806306177fea146104875780630e49d77e146104bc57806311ed0e77146104d157806313a06782146104e457806314a6bf0f146105075780631bbea34c1461051c57600080fd5b3661048257336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610480577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663ad5c46486040518163ffffffff1660e01b8152600401602060405180830381865afa158015610396573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103ba9190613ca2565b6001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03161461040b57604051631a38687560e21b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561046657600080fd5b505af115801561047a573d6000803e3d6000fd5b50505050505b005b600080fd5b34801561049357600080fd5b506104a76104a2366004613cbf565b610bd8565b60405190151581526020015b60405180910390f35b3480156104c857600080fd5b50610480610bed565b6104806104df366004613cf9565b610cb6565b3480156104f057600080fd5b506104f9610cd2565b6040519081526020016104b3565b34801561051357600080fd5b506104f9610ce1565b34801561052857600080fd5b50610480610537366004613d83565b610ceb565b34801561054857600080fd5b50610480610557366004613cbf565b610e26565b34801561056857600080fd5b50610480610577366004613e26565b610e91565b34801561058857600080fd5b506104f960035481565b34801561059e57600080fd5b506104f96112bb565b3480156105b357600080fd5b506104f96112d5565b3480156105c857600080fd5b506105d16113b6565b6040805192835264ffffffffff9091166020830152016104b3565b3480156105f857600080fd5b50610480610607366004613cbf565b6113f4565b34801561061857600080fd5b506106407f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016104b3565b34801561066457600080fd5b506104f9610673366004613e5b565b6114a2565b34801561068457600080fd5b506106ac7f000000000000000000000000000000000000000000000000000000000000000081565b60405162ffffff90911681526020016104b3565b3480156106cc57600080fd5b506104806106db366004613cbf565b6114bb565b6104806106ee366004613e74565b611583565b3480156106ff57600080fd5b5060055461071890600160281b900464ffffffffff1681565b60405164ffffffffff90911681526020016104b3565b34801561073a57600080fd5b506106407f000000000000000000000000000000000000000000000000000000000000000081565b34801561076e57600080fd5b5061048061077d366004613e5b565b611598565b34801561078e57600080fd5b5061048061079d366004613e5b565b611608565b3480156107ae57600080fd5b506104806107bd366004613edd565b6116f7565b3480156107ce57600080fd5b50610480611950565b3480156107e357600080fd5b506104806107f2366004613e5b565b611962565b34801561080357600080fd5b506106ac7f000000000000000000000000000000000000000000000000000000000000000081565b34801561083757600080fd5b506005546107189064ffffffffff1681565b34801561085557600080fd5b506008546107189064ffffffffff1681565b34801561087357600080fd5b50610887610882366004613e5b565b611980565b604080516001600160a01b039096168652602086019490945292840191909152606083015263ffffffff16608082015260a0016104b3565b3480156108cb57600080fd5b506106407f000000000000000000000000000000000000000000000000000000000000000081565b3480156108ff57600080fd5b506000546001600160a01b0316610640565b34801561091d57600080fd5b506104f9611abd565b34801561093257600080fd5b506104f9610941366004613e5b565b611aca565b34801561095257600080fd5b50610480610961366004613f16565b611af6565b34801561097257600080fd5b506104f960015481565b34801561098857600080fd5b506104f97f000000000000000000000000000000000000000000000000000000000000000081565b3480156109bc57600080fd5b506104f9611b13565b3480156109d157600080fd5b506104806109e0366004613f3b565b611bdf565b3480156109f157600080fd5b506104f960065481565b348015610a0757600080fd5b506104f97f000000000000000000000000000000000000000000000000000000000000000081565b348015610a3b57600080fd5b506107187f000000000000000000000000000000000000000000000000000000000000000081565b348015610a6f57600080fd5b50600554600160501b900460ff166104a7565b348015610a8e57600080fd5b506104f960075481565b348015610aa457600080fd5b506104f9610ab3366004613e5b565b611d14565b348015610ac457600080fd5b50610480610ad3366004613e5b565b611d5d565b348015610ae457600080fd5b506106407f000000000000000000000000000000000000000000000000000000000000000081565b348015610b1857600080fd5b50610480610b27366004613f5d565b611e44565b348015610b3857600080fd5b506104f9611f33565b348015610b4d57600080fd5b50610480610b5c366004613f9e565b611f3d565b348015610b6d57600080fd5b506005546106ac90600160581b900462ffffff1681565b348015610b9057600080fd5b506107187f000000000000000000000000000000000000000000000000000000000000000081565b348015610bc457600080fd5b50610480610bd3366004613cbf565b611f78565b6000610be48383611f8c565b90505b92915050565b60035415610c0e5760405163d26e2de960e01b815260040160405180910390fd5b60055464ffffffffff164211610c3757604051631c02820f60e21b815260040160405180910390fd5b600554600160281b900464ffffffffff164210610c89576005546040516238ddd760e41b815264ffffffffff4281166004830152600160281b9092049190911660248201526044015b60405180910390fd5b600554600160501b900460ff1615610cb457604051631cdde67b60e01b815260040160405180910390fd5b565b610cbe612626565b610ccc848484600085612653565b50505050565b6000610cdc612926565b905090565b6000610cdc612966565b7f000000000000000000000000000000000000000000000000000000000000000064ffffffffff164210610d325760405163ecdd1c2960e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663cd3293de6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d90573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610db49190613ca2565b6001600160a01b031663352e3a833386866040518463ffffffff1660e01b8152600401610de393929190613fbb565b60006040518083038186803b158015610dfb57600080fd5b505afa158015610e0f573d6000803e3d6000fd5b50505050610e1b612970565b610ccc338383612985565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610e6f576040516313bd2e8360e31b815260040160405180910390fd5b6000610e7b8383612aa1565b9050610e8c81600154600654612b7a565b505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610eda576040516313bd2e8360e31b815260040160405180910390fd5b600554600160281b900464ffffffffff16421015610f0b576040516302de694d60e41b815260040160405180910390fd5b60035415610f2c5760405163d26e2de960e01b815260040160405180910390fd5b6000610f36612c48565b600654610f43919061402f565b90506000610f518585612aa1565b90508160000361103a57821561101d577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166323b872dd86610fa36000546001600160a01b031690565b6040516001600160e01b031960e085901b1681526001600160a01b03928316600482015291166024820152604481018690526064016020604051808303816000875af1158015610ff7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061101b9190614042565b505b611033611028612c7e565b600154600654612b7a565b5050505050565b6110448584612ce5565b92506110508584612da8565b92508015801561106f5750600060075460065461106d919061402f565b115b156112735782156110825761108261405f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d1fa5e98306007546006546110c2919061402f565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b15801561110857600080fd5b505af115801561111c573d6000803e3d6000fd5b50505050600060075411156111ba5760075460405163375edc7760e11b815230600482015260248101919091527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636ebdb8ee90604401600060405180830381600087803b15801561119757600080fd5b505af11580156111ab573d6000803e3d6000fd5b505050506111ba600754613043565b6006546040516363b20c3360e11b8152600481019190915262ffffff7f00000000000000000000000000000000000000000000000000000000000000001660248201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063c764186690604401600060405180830381600087803b15801561124b57600080fd5b505af115801561125f573d6000803e3d6000fd5b5050505061126e600654613088565b61101d565b821561101d577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166323b872dd86610fa36000546001600160a01b031690565b6000610cdc6112c8612c48565b600654610673919061402f565b60006001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361133457600254610cdc907f0000000000000000000000000000000000000000000000000000000000000000614075565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a8a3e31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611392573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cdc9190614088565b6000806113cc6113c4612c7e565b60015461312b565b927f000000000000000000000000000000000000000000000000000000000000000092509050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663f09e9e3a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611452573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114769190613ca2565b6001600160a01b0316336001600160a01b03161461149657611496612626565b6000610e7b8383613186565b6000806114ae836131ed565b9050610be7611028612c7e565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663f09e9e3a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611519573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061153d9190613ca2565b6001600160a01b0316336001600160a01b03161461155d5761155d612626565b6000611567612c7e565b9050611574838383613232565b610e8c81600154600654612b7a565b61158b612626565b6110338585858585612653565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146115e1576040516313bd2e8360e31b815260040160405180910390fd5b80600360008282546115f39190614075565b909155506116059050620151806134a1565b50565b60405163aa5dd7f160e01b81523360048201526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116917f00000000000000000000000000000000000000000000000000000000000000009091169063aa5dd7f190602401602060405180830381865afa158015611692573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116b69190613ca2565b6001600160a01b0316146116dd576040516313bd2e8360e31b815260040160405180910390fd5b80600260008282546116ef9190614075565b909155505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611740576040516313bd2e8360e31b815260040160405180910390fd5b600554600160281b900464ffffffffff161561176e5760405162dc149f60e41b815260040160405180910390fd5b428164ffffffffff16108061181157507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316634665096d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156117dc573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061180091906140a1565b64ffffffffff168164ffffffffff16115b1561182f57604051637d9533a960e11b815260040160405180910390fd5b806005806101000a81548164ffffffffff021916908364ffffffffff160217905550816001600160a01b031663a035b1fe6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561188f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118b39190614088565b600181905550611923826001600160a01b031663730d48b76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156118fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061191e91906140be565b6134e2565b61194c7f00000000000000000000000000000000000000000000000000000000000000006135f1565b5050565b611958612626565b610cb460006135f1565b61196a612626565b611975816000613641565b611605611028612c7e565b600080808080336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146119cf576040516313bd2e8360e31b815260040160405180910390fd5b6119d7612c48565b5085600360008282546119ea9190614075565b90915550600090506119fa612c7e565b905086811015611a08578096505b60008115611a2e578188600754611a1f91906140e3565b611a2991906140fa565b611a31565b60005b905060008215611a59578289600654611a4a91906140e3565b611a5491906140fa565b611a5c565b60005b9050611a6782613043565b611a7081613088565b611a7c6203f4806134a1565b6000546001600160a01b0316999097509095507f000000000000000000000000000000000000000000000000000000000000000062ffffff16945092505050565b6000610cdc6113c4612c7e565b6000610be7827f0000000000000000000000000000000000000000000000000000000000000000613782565b611afe612626565b611b088282613641565b61194c611028612c7e565b600080670de0b6b3a7640000600154611b2a612c7e565b611b3491906140e3565b611b3e91906140fa565b905060008160065411611b5d57600654611b589083614075565b611b60565b60005b90507f000000000000000000000000000000000000000000000000000000000000000081600254611b91919061402f565b10611b9f5760009250505090565b806002547f0000000000000000000000000000000000000000000000000000000000000000611bce9190614075565b611bd89190614075565b9250505090565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611c28576040516313bd2e8360e31b815260040160405180910390fd5b600554600160281b900464ffffffffff164210611c75576005546040516238ddd760e41b815264ffffffffff4281166004830152600160281b909204919091166024820152604401610c80565b7f000000000000000000000000000000000000000000000000000000000000000082108015611caa5750611ca7612c7e565b82105b15611cc857604051633c80636b60e21b815260040160405180910390fd5b81600003611ce957604051633c80636b60e21b815260040160405180910390fd5b600354600003611cf95760048190555b8160036000828254611d0b919061402f565b90915550505050565b6000620f4240611d447f00000000000000000000000000000000000000000000000000000000000000008261411c565b611d539062ffffff16846140e3565b610be791906140fa565b60405163aa5dd7f160e01b81523360048201526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116917f00000000000000000000000000000000000000000000000000000000000000009091169063aa5dd7f190602401602060405180830381865afa158015611de7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e0b9190613ca2565b6001600160a01b031614611e32576040516313bd2e8360e31b815260040160405180910390fd5b80600260008282546116ef919061402f565b611e4c612626565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b031603611e9e57604051632e28519560e01b815260040160405180910390fd5b6000611ea8612c7e565b60405163a9059cbb60e01b81526001600160a01b038581166004830152602482018590529192509085169063a9059cbb906044016020604051808303816000875af1158015611efb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f1f9190614042565b50611f28612c7e565b8114610ccc57600080fd5b6000610cdc6137d8565b611f45612626565b6001600160a01b038116611f6f57604051631e4fbdf760e01b815260006004820152602401610c80565b611605816135f1565b611f80612626565b6000610e7b838361389d565b60405163aa5dd7f160e01b81526001600160a01b0383811660048301526000917f00000000000000000000000000000000000000000000000000000000000000008216917f0000000000000000000000000000000000000000000000000000000000000000169063aa5dd7f190602401602060405180830381865afa158015612019573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061203d9190613ca2565b6001600160a01b03161461205357506000610be7565b82306001600160a01b0382160361206e576000915050610be7565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b031663d8dfeb456040518163ffffffff1660e01b8152600401602060405180830381865afa1580156120d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120fa9190613ca2565b6001600160a01b031614612112576000915050610be7565b806001600160a01b031663787a08a66040518163ffffffff1660e01b8152600401602060405180830381865afa158015612150573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061217491906140a1565b64ffffffffff16421161218b576000915050610be7565b806001600160a01b0316634665096d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156121c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121ed91906140a1565b64ffffffffff164210612204576000915050610be7565b6000816001600160a01b03166324e657fe6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612244573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122689190614088565b1115612278576000915050610be7565b806001600160a01b031663c2b6b58c6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156122b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122da9190614042565b156122e9576000915050610be7565b806001600160a01b031663a035b1fe6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612327573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061234b9190614088565b83111561235c576000915050610be7565b806001600160a01b031663ba5d30786040518163ffffffff1660e01b8152600401602060405180830381865afa15801561239a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123be9190614088565b6000036123cf576000915050610be7565b683635c9adc5dea00000816001600160a01b031663ba5d30786040518163ffffffff1660e01b8152600401602060405180830381865afa158015612417573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061243b9190614088565b101561244b576000915050610be7565b42816001600160a01b031663f3f480d96040518163ffffffff1660e01b8152600401602060405180830381865afa15801561248a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124ae91906140a1565b826001600160a01b031663787a08a66040518163ffffffff1660e01b8152600401602060405180830381865afa1580156124ec573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061251091906140a1565b61251a9190614137565b64ffffffffff161115612531576000915050610be7565b806001600160a01b031663f3f480d96040518163ffffffff1660e01b8152600401602060405180830381865afa15801561256f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061259391906140a1565b6125a49064ffffffffff164261402f565b816001600160a01b0316634665096d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156125e2573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061260691906140a1565b64ffffffffff161161261c576000915050610be7565b5060019392505050565b6000546001600160a01b03163314610cb45760405163118cdaa760e01b8152336004820152602401610c80565b34156127a1577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663ad5c46486040518163ffffffff1660e01b8152600401602060405180830381865afa1580156126b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126db9190613ca2565b6001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03161461272c57604051631a38687560e21b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561278757600080fd5b505af115801561279b573d6000803e3d6000fd5b50505050505b60006127ab612c7e565b90508085111561286a576001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166323b872dd33306127f0858a614075565b6040516001600160e01b031960e086901b1681526001600160a01b03938416600482015292909116602483015260448201526064016020604051808303816000875af1158015612844573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128689190614042565b505b6006548610156128a257600061287e612c48565b60065461288b919061402f565b905061289f61289a8883614075565b6131ed565b50505b808510156128de5781156128c9576128c3336128be8784614075565b61389d565b506128de565b6128dc336128d78784614075565b613186565b505b6006548611156129005761290033600654886128fa9190614075565b87613232565b6001548414612913576129138484613641565b61291e858588612b7a565b505050505050565b60006129596129336137d8565b7f0000000000000000000000000000000000000000000000000000000000000000613782565b600654610cdc919061402f565b60006129596137d8565b6005805460ff60501b1916600160501b179055565b8060008190036129a85760405163017636cb60e71b815260040160405180910390fd5b6101f48111156129d6576040516368f2ea7760e01b8152600481018290526101f46024820152604401610c80565b836001600160a01b03167faca80c800ec0d2aa9d9d31b7f886a1dd3067d4676abc637626a18ffb9381653d8484604051612a1192919061417d565b60405180910390a260405163f32ddc2d60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063f32ddc2d90612a6990879087908790600401614199565b600060405180830381600087803b158015612a8357600080fd5b505af1158015612a97573d6000803e3d6000fd5b5050505050505050565b60008115612b3e5760405163a9059cbb60e01b81526001600160a01b038481166004830152602482018490527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906044016020604051808303816000875af1158015612b18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b3c9190614042565b505b6000612b48612c7e565b90507f0000000000000000000000000000000000000000000000000000000000000000811015610be457610be4612970565b60408051848152602081018490529081018290527f9483a26ad376f30b5199a79e75df3bb05158c4ee32a348f53e83245a5e50c86e9060600160405180910390a160405163d6d87bdb60e01b81526004810184905260248101839052604481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063d6d87bdb90606401600060405180830381600087803b158015612c2b57600080fd5b505af1158015612c3f573d6000803e3d6000fd5b50505050505050565b6000612c526137d8565b9050600754811115612c645760078190555b6008805464ffffffffff19164264ffffffffff1617905590565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015611392573d6000803e3d6000fd5b6000808260075411612cf957600754612cfb565b825b90508015612da05760405163375edc7760e11b81526001600160a01b038581166004830152602482018390527f00000000000000000000000000000000000000000000000000000000000000001690636ebdb8ee90604401600060405180830381600087803b158015612d6d57600080fd5b505af1158015612d81573d6000803e3d6000fd5b50505050612d8e81613043565b612d988184614075565b915050610be7565b509092915050565b6006546040516302dc1ca760e31b8152600481019190915262ffffff7f000000000000000000000000000000000000000000000000000000000000000016602482015260009081906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906316e0e53890604401602060405180830381865afa158015612e41573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e659190614088565b9050600081600654612e779190614075565b90506000818511612e885784612e8a565b815b9050801561303957604051633824f22960e21b81526004810182905262ffffff7f00000000000000000000000000000000000000000000000000000000000000001660248201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063e093c8a490604401602060405180830381865afa158015612f25573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f499190614088565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663315f3e7289847f00000000000000000000000000000000000000000000000000000000000000006040518463ffffffff1660e01b8152600401612fbd939291906141c7565b6020604051808303816000875af1158015612fdc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130009190614088565b905061300c8383614075565b811461301a5761301a61405f565b61302382613088565b61302d8388614075565b95505050505050610be7565b5092949350505050565b6007548111156130765760075461305a9082614075565b604051635795d46960e11b8152600401610c8091815260200190565b80600760008282546116ef9190614075565b60065481111561309f5760065461305a9082614075565b604051635be980f560e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635be980f590602401600060405180830381600087803b15801561310157600080fd5b505af1158015613115573d6000803e3d6000fd5b5050505080600660008282546116ef9190614075565b6003546000901561313f5750600454610be7565b8260000361314e575080610be7565b600083670de0b6b3a7640000613162612926565b61316c91906140e3565b61317691906140fa565b9050828110612da0579392505050565b60055460009064ffffffffff1642116131b257604051631c02820f60e21b815260040160405180910390fd5b600354156131d35760405163d26e2de960e01b815260040160405180910390fd5b60006131df8484612aa1565b9050610be481600154613a24565b60006131f7612c48565b508160000361320857506000919050565b816132133382612ce5565b905061321f3382613ac4565b905061322b8184614075565b9392505050565b600354156132535760405163d26e2de960e01b815260040160405180910390fd5b60055464ffffffffff16421161327c57604051631c02820f60e21b815260040160405180910390fd5b600554600160281b900464ffffffffff1642106132c9576005546040516238ddd760e41b815264ffffffffff4281166004830152600160281b909204919091166024820152604401610c80565b600554600160501b900460ff16156132f457604051631cdde67b60e01b815260040160405180910390fd5b6132fc6112d5565b82111561332e578161330c6112d5565b604051634779077960e11b815260048101929092526024820152604401610c80565b613336612c48565b506133607f00000000000000000000000000000000000000000000000000000000000000006134e2565b604051630cfb636f60e41b8152600481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063cfb636f090602401600060405180830381600087803b1580156133c257600080fd5b505af11580156133d6573d6000803e3d6000fd5b505060405163165203b760e31b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016925063b2901db8915061344a90869086907f0000000000000000000000000000000000000000000000000000000000000000906004016141c7565b600060405180830381600087803b15801561346457600080fd5b505af1158015613478573d6000803e3d6000fd5b50505050816006600082825461348e919061402f565b92505081905550610e8c81600154613a24565b60006134ad8242614137565b60055490915064ffffffffff908116908216111561194c576005805464ffffffffff831664ffffffffff199091161790555050565b807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663664e97046040518163ffffffff1660e01b8152600401602060405180830381865afa158015613541573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135659190613ca2565b6001600160a01b03166306a7b3766040518163ffffffff1660e01b8152600401602060405180830381865afa1580156135a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135c691906140be565b6135d091906141ed565b6005600b6101000a81548162ffffff021916908362ffffff16021790555050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600354156136625760405163d26e2de960e01b815260040160405180910390fd5b600554600160281b900464ffffffffff1642106136af576005546040516238ddd760e41b815264ffffffffff4281166004830152600160281b909204919091166024820152604401610c80565b600554600160501b900460ff16156136da57604051631cdde67b60e01b815260040160405180910390fd5b6001548211156137535760055464ffffffffff16421161370d57604051631c02820f60e21b815260040160405180910390fd5b6001600160a01b03811661372c576137276203f4806134a1565b613764565b6137368183611f8c565b61372757604051635d8903cd60e11b815260040160405180910390fd5b61376461375e612c7e565b83613a24565b61194c826137706112d5565b60065461377d919061402f565b613bc0565b600082156137cf5761379782620f424061411c565b62ffffff1660016137ab85620f42406140e3565b6137b59190614075565b6137bf91906140fa565b6137ca90600161402f565b610be4565b50600092915050565b600754600854429064ffffffffff16811180156137f757506000600654115b15613899576008546000906138139064ffffffffff1683614075565b6005549091506801b5a660ea44b80000908290600160581b900462ffffff1661385f7f0000000000000000000000000000000000000000000000000000000000000000620f424061411c565b62ffffff1660065461387191906140e3565b61387b91906140e3565b61388591906140e3565b61388f91906140fa565b611bd8908461402f565b5090565b60055460009064ffffffffff1642116138c957604051631c02820f60e21b815260040160405180910390fd5b600354156138ea5760405163d26e2de960e01b815260040160405180910390fd5b81156139e057604051632e1a7d4d60e01b8152600481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561395257600080fd5b505af1158015613966573d6000803e3d6000fd5b505050506000836001600160a01b03168360405160006040518083038185875af1925050503d80600081146139b7576040519150601f19603f3d011682016040523d82523d6000602084013e6139bc565b606091505b50509050806139de57604051633d2cec6f60e21b815260040160405180910390fd5b505b60006139ea612c7e565b90507f0000000000000000000000000000000000000000000000000000000000000000811015613a1c57613a1c612970565b610be4816001545b60007f00000000000000000000000000000000000000000000000000000000000000008310613a535782613a56565b60005b90506000613a62612926565b9050613a76670de0b6b3a7640000826140e3565b613a8084846140e3565b1015610ccc57613a9083836140e3565b613aa2670de0b6b3a7640000836140e3565b604051632c1f8ef160e21b815260048101929092526024820152604401610c80565b6000808260065411613ad857600654613ada565b825b90508015612da0576040516318af9f3960e11b81526000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063315f3e7290613b5590889086907f0000000000000000000000000000000000000000000000000000000000000000906004016141c7565b6020604051808303816000875af1158015613b74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b989190614088565b9050613ba382613088565b613bad8183614075565b613bb79085614075565b92505050610be7565b6000613bca612c7e565b90507f000000000000000000000000000000000000000000000000000000000000000064ffffffffff164210158015613c0f5750600154613c0c9060026140e3565b83115b15613c4657826001546002613c2491906140e3565b6040516387ebe85d60e01b815260048101929092526024820152604401610c80565b613c58670de0b6b3a7640000836140e3565b613c6282856140e3565b1115613c86578281613c7c670de0b6b3a7640000856140e3565b613c2491906140fa565b5050600155565b6001600160a01b038116811461160557600080fd5b600060208284031215613cb457600080fd5b8151610be481613c8d565b60008060408385031215613cd257600080fd5b8235613cdd81613c8d565b946020939093013593505050565b801515811461160557600080fd5b60008060008060808587031215613d0f57600080fd5b8435935060208501359250604085013591506060850135613d2f81613ceb565b939692955090935050565b60008083601f840112613d4c57600080fd5b50813567ffffffffffffffff811115613d6457600080fd5b602083019150836020828501011115613d7c57600080fd5b9250929050565b60008060008060408587031215613d9957600080fd5b843567ffffffffffffffff811115613db057600080fd5b8501601f81018713613dc157600080fd5b803567ffffffffffffffff811115613dd857600080fd5b8760208260051b8401011115613ded57600080fd5b60209182019550935085013567ffffffffffffffff811115613e0e57600080fd5b613e1a87828801613d3a565b95989497509550505050565b600080600060608486031215613e3b57600080fd5b8335613e4681613c8d565b95602085013595506040909401359392505050565b600060208284031215613e6d57600080fd5b5035919050565b600080600080600060a08688031215613e8c57600080fd5b8535945060208601359350604086013592506060860135613eac81613c8d565b91506080860135613ebc81613ceb565b809150509295509295909350565b64ffffffffff8116811461160557600080fd5b60008060408385031215613ef057600080fd5b8235613efb81613c8d565b91506020830135613f0b81613eca565b809150509250929050565b60008060408385031215613f2957600080fd5b823591506020830135613f0b81613c8d565b60008060408385031215613f4e57600080fd5b50508035926020909101359150565b600080600060608486031215613f7257600080fd5b8335613f7d81613c8d565b92506020840135613f8d81613c8d565b929592945050506040919091013590565b600060208284031215613fb057600080fd5b8135610be481613c8d565b6001600160a01b0384168152604060208201819052810182905260008360608301825b8581101561400e578235613ff181613c8d565b6001600160a01b0316825260209283019290910190600101613fde565b509695505050505050565b634e487b7160e01b600052601160045260246000fd5b80820180821115610be757610be7614019565b60006020828403121561405457600080fd5b8151610be481613ceb565b634e487b7160e01b600052600160045260246000fd5b81810381811115610be757610be7614019565b60006020828403121561409a57600080fd5b5051919050565b6000602082840312156140b357600080fd5b8151610be481613eca565b6000602082840312156140d057600080fd5b815162ffffff81168114610be457600080fd5b8082028115828204841417610be757610be7614019565b60008261411757634e487b7160e01b600052601260045260246000fd5b500490565b62ffffff8281168282160390811115610be757610be7614019565b64ffffffffff8181168382160190811115610be757610be7614019565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b602081526000614191602083018486614154565b949350505050565b6001600160a01b03841681526040602082018190526000906141be9083018486614154565b95945050505050565b6001600160a01b03939093168352602083019190915262ffffff16604082015260600190565b62ffffff8181168382160190811115610be757610be761401956fea2646970667358221220eb9d5898312a137d8f4911ff30ce09bd7944d020bf79bde95617bcb43b192e5c64736f6c634300081a0033a264697066735822122004263ed2656985c139e0e8ead84db8a1b5737e3a1a4ce347a17a9be94061524e64736f6c634300081a0033","name":"PositionFactory","is_blueprint":false,"license_type":"none","is_fully_verified":true,"is_verified_via_eth_bytecode_db":false,"language":"solidity","evm_version":"paris","can_be_visualized_via_sol2uml":true,"is_verified_via_sourcify":false,"additional_sources":[{"file_path":"contracts/MintingHubV3/interface/IPosition.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\ninterface IPosition {\n    function hub() external view returns (address);\n\n    function collateral() external view returns (IERC20);\n\n    function minimumCollateral() external view returns (uint256);\n\n    function price() external view returns (uint256);\n\n    function virtualPrice() external view returns (uint256);\n\n    function challengedAmount() external view returns (uint256);\n\n    function original() external view returns (address payable);\n\n    function expiration() external view returns (uint40);\n\n    function cooldown() external view returns (uint40);\n\n    function limit() external view returns (uint256);\n\n    function challengePeriod() external view returns (uint40);\n\n    function start() external view returns (uint40);\n\n    function riskPremiumPPM() external view returns (uint24);\n\n    function reserveContribution() external view returns (uint24);\n\n    function principal() external view returns (uint256);\n\n    function interest() external view returns (uint256);\n\n    function lastAccrual() external view returns (uint40);\n\n    function initialize(address parent, uint40 _expiration) external;\n\n    function assertCloneable() external;\n\n    function notifyMint(uint256 mint_) external;\n\n    function notifyRepaid(uint256 repaid_) external;\n\n    function availableForClones() external view returns (uint256);\n\n    function availableForMinting() external view returns (uint256);\n\n    function deny(address[] calldata helpers, string calldata message) external;\n\n    function getUsableMint(uint256 totalMint) external view returns (uint256);\n\n    function getMintAmount(uint256 usableMint) external view returns (uint256);\n\n    function adjust(uint256 newPrincipal, uint256 newCollateral, uint256 newPrice, bool withdrawAsNative) external payable;\n\n    function adjustPrice(uint256 newPrice) external;\n\n    function adjustPriceWithReference(uint256 newPrice, address referencePosition) external;\n\n    function adjustWithReference(uint256 newPrincipal, uint256 newCollateral, uint256 newPrice, address referencePosition, bool withdrawAsNative) external payable;\n\n    function isValidPriceReference(address referencePosition, uint256 newPrice) external view returns (bool);\n\n    function isClosed() external view returns (bool);\n\n    function mint(address target, uint256 amount) external;\n\n    function getDebt() external view returns (uint256);\n\n    function getInterest() external view returns (uint256);\n\n    function repay(uint256 amount) external returns (uint256);\n\n    function repayFull() external returns (uint256);\n\n    function forceSale(address buyer, uint256 colAmount, uint256 proceeds) external;\n\n    function rescueToken(address token, address target, uint256 amount) external;\n\n    function withdrawCollateral(address target, uint256 amount) external;\n\n    function withdrawCollateralAsNative(address target, uint256 amount) external;\n\n    function transferChallengedCollateral(address target, uint256 amount) external;\n\n    function challengeData() external view returns (uint256 liqPrice, uint40 phase);\n\n    function notifyChallengeStarted(uint256 size, uint256 _price) external;\n\n    function notifyChallengeAverted(uint256 size) external;\n\n    function notifyChallengeSucceeded(\n        uint256 _size\n    ) external returns (address, uint256, uint256, uint256, uint32);\n}\n"},{"file_path":"@openzeppelin/contracts/utils/Context.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n    function _msgSender() internal view virtual returns (address) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view virtual returns (bytes calldata) {\n        return msg.data;\n    }\n\n    function _contextSuffixLength() internal view virtual returns (uint256) {\n        return 0;\n    }\n}\n"},{"file_path":"contracts/MintingHubV3/Position.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\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 {IWrappedNative} from \"../interface/IWrappedNative.sol\";\nimport {Ownable} from \"@openzeppelin/contracts/access/Ownable.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.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    uint256 private constant MAX_MESSAGE_LENGTH = 500;\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 payable 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 MessageTooLong(uint256 length, uint256 maxLength);\n    error EmptyMessage();\n    error PriceTooHigh(uint256 newPrice, uint256 maxPrice);\n    error CannotRescueCollateral();\n    error InvalidPriceReference();\n    error NativeTransferFailed();\n    error NativeOnlyForWETH();\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 = payable(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(payable(parent)).price();\n        _fixRateToLeadrate(Position(payable(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        _emitDenied(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    function _emitUpdate(uint256 _collateral, uint256 _price, uint256 _principal) internal {\n        emit MintingUpdate(_collateral, _price, _principal);\n        IMintingHub(hub).emitPositionUpdate(_collateral, _price, _principal);\n    }\n\n    function _emitDenied(address denier, string calldata message) internal {\n        uint256 messageLength = bytes(message).length;\n        if (messageLength == 0) revert EmptyMessage();\n        if (messageLength > MAX_MESSAGE_LENGTH) revert MessageTooLong(messageLength, MAX_MESSAGE_LENGTH);\n        emit PositionDenied(denier, message);\n        IMintingHub(hub).emitPositionDenied(denier, message);\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, bool withdrawAsNative) external payable onlyOwner {\n        _adjust(newPrincipal, newCollateral, newPrice, address(0), withdrawAsNative);\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, address(0));\n        _emitUpdate(_collateralBalance(), price, principal);\n    }\n\n    /**\n     * @notice Adjust the liquidation price using a reference position to skip the 3-day cooldown.\n     * The reference must satisfy all validity checks (same hub, same collateral, meaningful principal, etc.).\n     */\n    function adjustPriceWithReference(uint256 newPrice, address referencePosition) external onlyOwner {\n        _adjustPrice(newPrice, referencePosition);\n        _emitUpdate(_collateralBalance(), price, principal);\n    }\n\n    /**\n     * @notice \"All in one\" function with reference position support.\n     */\n    function adjustWithReference(uint256 newPrincipal, uint256 newCollateral, uint256 newPrice, address referencePosition, bool withdrawAsNative) external payable onlyOwner {\n        _adjust(newPrincipal, newCollateral, newPrice, referencePosition, withdrawAsNative);\n    }\n\n    function _adjust(uint256 newPrincipal, uint256 newCollateral, uint256 newPrice, address referencePosition, bool withdrawAsNative) internal {\n        if (msg.value > 0) {\n            if (address(collateral) != IMintingHub(hub).WETH()) revert NativeOnlyForWETH();\n            IWrappedNative(address(collateral)).deposit{value: msg.value}();\n        }\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            if (withdrawAsNative) {\n                _withdrawCollateralAsNative(msg.sender, colbal - newCollateral);\n            } else {\n                _withdrawCollateral(msg.sender, colbal - newCollateral);\n            }\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, referencePosition);\n        }\n        _emitUpdate(newCollateral, newPrice, newPrincipal);\n    }\n\n    function _adjustPrice(uint256 newPrice, address referencePosition) internal noChallenge alive backed {\n        if (newPrice > price) {\n            if (block.timestamp <= cooldown) revert Hot();\n            if (referencePosition == address(0)) {\n                _restrictMinting(3 days);\n            } else if (!_isValidPriceReference(referencePosition, newPrice)) {\n                revert InvalidPriceReference();\n            }\n        } else {\n            _checkCollateral(_collateralBalance(), newPrice);\n        }\n        _setPrice(newPrice, principal + availableForMinting());\n    }\n\n    /**\n     * @notice Checks whether a reference position is valid for skipping the cooldown on a price increase.\n     */\n    function isValidPriceReference(address referencePosition, uint256 newPrice) external view returns (bool) {\n        return _isValidPriceReference(referencePosition, newPrice);\n    }\n\n    function _isValidPriceReference(address referencePosition, uint256 newPrice) internal view returns (bool) {\n        // 1. Reference is a registered position created by the same hub\n        if (deuro.getPositionParent(referencePosition) != hub) return false;\n        IPosition ref = IPosition(referencePosition);\n        // 2. Reference is not this position itself\n        if (referencePosition == address(this)) return false;\n        // 3. Same collateral token\n        if (address(ref.collateral()) != address(collateral)) return false;\n        // 4. Reference not in cooldown\n        if (block.timestamp <= ref.cooldown()) return false;\n        // 5. Reference not expired\n        if (block.timestamp >= ref.expiration()) return false;\n        // 6. Reference not challenged\n        if (ref.challengedAmount() > 0) return false;\n        // 7. Reference not closed\n        if (ref.isClosed()) return false;\n        // 8. newPrice <= reference price\n        if (newPrice > ref.price()) return false;\n        // 9. Reference principal > 0\n        if (ref.principal() == 0) return false;\n        // 10. Reference principal >= 1000 dEURO (meaningful skin-in-the-game)\n        if (ref.principal() < 1000 * 10 ** 18) return false;\n        // 11. Reference has been out of cooldown for >= challengePeriod\n        if (ref.cooldown() + ref.challengePeriod() > block.timestamp) return false;\n        // 12. Reference has meaningful remaining life (can still be challenged)\n        if (ref.expiration() <= block.timestamp + ref.challengePeriod()) return false;\n        return true;\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        _emitUpdate(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 * (1_000_000 - reserveContribution) * fixedAnnualRatePPM * delta) / (365 days * 1_000_000 * 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        _emitUpdate(_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.\n     */\n    function _notifyInterestPaid(uint256 amount) internal {\n        if (amount > interest) revert RepaidTooMuch(amount - interest);\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            _emitUpdate(_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        _emitUpdate(_collateralBalance(), price, principal);\n    }\n\n    /**\n     * @notice Rescue any ERC20 token that might have ended up on this address accidentally.\n     * Cannot be used to withdraw collateral — use withdrawCollateral(...) for that.\n     */\n    function rescueToken(address token, address target, uint256 amount) external onlyOwner {\n        if (token == address(collateral)) revert CannotRescueCollateral();\n        uint256 balance = _collateralBalance();\n        IERC20(token).transfer(target, amount);\n        require(balance == _collateralBalance()); // guard against double-entry-point tokens\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        _emitUpdate(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 Withdraw collateral as native coin (unwraps WETH to ETH).\n     */\n    function withdrawCollateralAsNative(address target, uint256 amount) public onlyOwner {\n        uint256 balance = _withdrawCollateralAsNative(target, amount);\n        _emitUpdate(balance, price, principal);\n    }\n\n    function _withdrawCollateralAsNative(address target, uint256 amount) internal noCooldown noChallenge returns (uint256) {\n        if (amount > 0) {\n            IWrappedNative(address(collateral)).withdraw(amount);\n            (bool success, ) = target.call{value: amount}(\"\");\n            if (!success) revert NativeTransferFailed();\n        }\n        uint256 balance = _collateralBalance();\n        if (balance < minimumCollateral) _close();\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        _emitUpdate(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    /**\n     * @notice Auto-wraps ETH sent to the position. Guard prevents recursion during WETH.withdraw().\n     */\n    receive() external payable {\n        if (msg.sender != address(collateral)) {\n            if (address(collateral) != IMintingHub(hub).WETH()) revert NativeOnlyForWETH();\n            IWrappedNative(address(collateral)).deposit{value: msg.value}();\n        }\n    }\n}\n"},{"file_path":"contracts/MintingHubV3/PositionRoller.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IDecentralizedEURO} from \"../interface/IDecentralizedEURO.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {IMintingHub} from \"./interface/IMintingHub.sol\";\nimport {IPosition} from \"./interface/IPosition.sol\";\nimport {IWrappedNative} from \"../interface/IWrappedNative.sol\";\nimport {Ownable} from \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @title PositionRoller\n *\n * Helper to roll over a debt from an old position to a new one.\n * Both positions should have the same collateral. Otherwise, it does not make much sense.\n */\ncontract PositionRoller {\n    IDecentralizedEURO private deuro;\n\n    error NotOwner(address pos);\n    error NotPosition(address pos);\n    error NativeTransferFailed();\n\n    event Roll(address source, uint256 collWithdraw, uint256 repay, address target, uint256 collDeposit, uint256 mint);\n\n    constructor(address deuro_) {\n        deuro = IDecentralizedEURO(deuro_);\n    }\n\n    /**\n     * Convenience method to roll an old position into a new one.\n     *\n     * Pre-condition: an allowance for the roller to spend the collateral asset on behalf of the caller,\n     * i.e., one should set collateral.approve(roller, collateral.balanceOf(sourcePosition)).\n     *\n     * The following is assumed:\n     * - If the limit of the target position permits, the user wants to roll everything.\n     * - The user does not want to add additional collateral, but excess collateral is returned.\n     * - If not enough can be minted in the new position, it is acceptable for the roller to use dEURO from the msg.sender.\n     */\n    function rollFully(IPosition source, IPosition target) external {\n        rollFullyWithExpiration(source, target, target.expiration());\n    }\n\n    /**\n     * Like rollFully, but with a custom expiration date for the new position.\n     */\n    function rollFullyWithExpiration(IPosition source, IPosition target, uint40 expiration) public {\n        (uint256 repay, uint256 collWithdraw, uint256 mint, uint256 collDeposit) =\n            _calculateRollParams(source, target, 0);\n        roll(source, repay, collWithdraw, target, mint, collDeposit, expiration);\n    }\n\n    /**\n     * Rolls the source position into the target position using a flash loan.\n     * Both the source and the target position must recognize this roller.\n     * It is the responsibility of the caller to ensure that both positions are valid contracts.\n     *\n     * @param source The source position, must be owned by the msg.sender.\n     * @param repay The amount of principal to repay from the source position using a flash loan, freeing up some or all collateral .\n     * @param collWithdraw Collateral to move from the source position to the msg.sender.\n     * @param target The target position. If not owned by msg.sender or if it does not have the desired expiration,\n     *               it is cloned to create a position owned by the msg.sender.\n     * @param mint The amount to be minted from the target position using collateral from msg.sender.\n     * @param collDeposit The amount of collateral to be sent from msg.sender to the target position.\n     * @param expiration The desired expiration date for the target position.\n     */\n    function roll(\n        IPosition source,\n        uint256 repay,\n        uint256 collWithdraw,\n        IPosition target,\n        uint256 mint,\n        uint256 collDeposit,\n        uint40 expiration\n    ) public valid(source) valid(target) own(source) {\n        deuro.mint(address(this), repay); // take a flash loan\n        uint256 used = source.repay(repay);\n        source.withdrawCollateral(msg.sender, collWithdraw);\n        if (mint > 0) {\n            IERC20 targetCollateral = IERC20(target.collateral());\n            bool needsClone = Ownable(address(target)).owner() != msg.sender || expiration != target.expiration();\n            if (needsClone) {\n                targetCollateral.transferFrom(msg.sender, address(this), collDeposit); // get the new collateral\n                targetCollateral.approve(target.hub(), collDeposit); // approve the new collateral and clone:\n                target = _cloneTargetPosition(target, collDeposit, mint, expiration);\n            } else {\n                // We can roll into the provided existing position.\n                // We do not verify whether the target position was created by the known minting hub in order\n                // to allow positions to be rolled into future versions of the minting hub.\n                targetCollateral.transferFrom(msg.sender, address(target), collDeposit);\n                target.mint(msg.sender, mint);\n            }\n        }\n\n        // Transfer remaining flash loan to caller for repayment\n        if (repay > used) {\n            deuro.transfer(msg.sender, repay - used);\n        }\n\n        deuro.burnFrom(msg.sender, repay); // repay the flash loan\n        emit Roll(address(source), collWithdraw, repay, address(target), collDeposit, mint);\n    }\n\n    /**\n     * @notice Roll a position using native coin (ETH) as additional collateral.\n     */\n    function rollFullyNative(IPosition source, IPosition target) external payable {\n        rollFullyNativeWithExpiration(source, target, target.expiration());\n    }\n\n    function rollFullyNativeWithExpiration(IPosition source, IPosition target, uint40 expiration) public payable {\n        (uint256 repay, uint256 collWithdraw, uint256 mint, uint256 collDeposit) =\n            _calculateRollParams(source, target, msg.value);\n        rollNative(source, repay, collWithdraw, target, mint, collDeposit, expiration);\n    }\n\n    /**\n     * @notice Roll with native coin support. Wraps msg.value, withdraws source collateral to the roller,\n     * deposits to target, and returns excess as native coin.\n     */\n    function rollNative(\n        IPosition source,\n        uint256 repay,\n        uint256 collWithdraw,\n        IPosition target,\n        uint256 mint,\n        uint256 collDeposit,\n        uint40 expiration\n    ) public payable valid(source) valid(target) own(source) {\n        IERC20 collateralToken = source.collateral();\n\n        deuro.mint(address(this), repay); // take a flash loan\n        uint256 used = source.repay(repay);\n        source.withdrawCollateral(address(this), collWithdraw);\n\n        // Wrap any ETH sent as additional collateral (after flash loan to avoid idle WETH)\n        if (msg.value > 0) {\n            IWrappedNative(address(collateralToken)).deposit{value: msg.value}();\n        }\n\n        if (mint > 0) {\n            IERC20 targetCollateral = IERC20(target.collateral());\n            bool needsClone = Ownable(address(target)).owner() != msg.sender || expiration != target.expiration();\n            if (needsClone) {\n                targetCollateral.approve(target.hub(), collDeposit);\n                target = _cloneTargetPosition(target, collDeposit, mint, expiration);\n            } else {\n                targetCollateral.transfer(address(target), collDeposit);\n                target.mint(msg.sender, mint);\n            }\n        }\n\n        if (repay > used) {\n            deuro.transfer(msg.sender, repay - used);\n        }\n\n        deuro.burnFrom(msg.sender, repay); // repay the flash loan\n\n        // Return excess collateral as native coin\n        uint256 remaining = collateralToken.balanceOf(address(this));\n        if (remaining > 0) {\n            IWrappedNative(address(collateralToken)).withdraw(remaining);\n            (bool success, ) = msg.sender.call{value: remaining}(\"\");\n            if (!success) revert NativeTransferFailed();\n        }\n\n        emit Roll(address(source), collWithdraw, repay, address(target), collDeposit, mint);\n    }\n\n    function _calculateRollParams(\n        IPosition source,\n        IPosition target,\n        uint256 extraCollateral\n    ) internal view returns (uint256 repay, uint256 collWithdraw, uint256 mint, uint256 collDeposit) {\n        require(source.collateral() == target.collateral());\n        uint256 principal = source.principal();\n        uint256 interest = source.getInterest();\n        uint256 usableMint = source.getUsableMint(principal) + interest;\n        uint256 mintAmount = target.getMintAmount(usableMint);\n        uint256 collateralAvailable = IERC20(source.collateral()).balanceOf(address(source));\n        uint256 totalAvailable = collateralAvailable + extraCollateral;\n        uint256 targetPrice = target.price();\n        uint256 depositAmount = (mintAmount * 10 ** 18 + targetPrice - 1) / targetPrice;\n        if (depositAmount > totalAvailable) {\n            depositAmount = totalAvailable;\n            mintAmount = (depositAmount * targetPrice) / 10 ** 18;\n        }\n        repay = principal + interest;\n        collWithdraw = collateralAvailable;\n        mint = mintAmount;\n        collDeposit = depositAmount;\n    }\n\n    /**\n     * Clones the target position and mints the specified amount using the given collateral.\n     */\n    function _cloneTargetPosition(\n        IPosition target,\n        uint256 collDeposit,\n        uint256 mint,\n        uint40 expiration\n    ) internal returns (IPosition) {\n        return IPosition(\n            IMintingHub(target.hub()).clone(msg.sender, address(target), collDeposit, mint, expiration, 0)\n        );\n    }\n\n    modifier own(IPosition pos) {\n        if (Ownable(address(pos)).owner() != msg.sender) revert NotOwner(address(pos));\n        _;\n    }\n\n    modifier valid(IPosition pos) {\n        if (deuro.getPositionParent(address(pos)) == address(0x0)) revert NotPosition(address(pos));\n        _;\n    }\n\n    /**\n     * @dev Required for WETH.withdraw() callbacks and receiving excess native coin.\n     */\n    receive() external payable {}\n}\n"},{"file_path":"contracts/MintingHubV3/interface/IMintingHub.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.10;\n\nimport {ILeadrate} from \"../../interface/ILeadrate.sol\";\nimport {IPosition} from \"./IPosition.sol\";\nimport {PositionRoller} from \"../PositionRoller.sol\";\n\ninterface IMintingHub {\n    // Events for centralized position monitoring (emitted by hub, not individual positions)\n    event PositionUpdate(address indexed position, uint256 collateral, uint256 price, uint256 principal);\n\n    event PositionDeniedByGovernance(address indexed position, address indexed denier, string message);\n\n    function RATE() external view returns (ILeadrate);\n\n    function ROLLER() external view returns (PositionRoller);\n\n    function WETH() external view returns (address);\n\n    // Position event forwarding functions\n    function emitPositionUpdate(uint256 collateral, uint256 price, uint256 principal) external;\n\n    function emitPositionDenied(address denier, string calldata message) external;\n\n    function challenge(\n        address _positionAddr,\n        uint256 _collateralAmount,\n        uint256 minimumPrice\n    ) external payable returns (uint256);\n\n    function bid(uint256 _challengeNumber, uint256 size, bool postponeCollateralReturn) external;\n\n    function bid(\n        uint256 _challengeNumber,\n        uint256 size,\n        bool postponeCollateralReturn,\n        bool returnCollateralAsNative\n    ) external;\n\n    function returnPostponedCollateral(address collateral, address target) external;\n\n    function returnPostponedCollateral(address collateral, address target, bool asNative) external;\n\n    function buyExpiredCollateral(IPosition pos, uint256 upToAmount) external returns (uint256);\n\n    function buyExpiredCollateral(IPosition pos, uint256 upToAmount, bool receiveAsNative) external returns (uint256);\n\n    function clone(\n        address owner,\n        address parent,\n        uint256 _initialCollateral,\n        uint256 _initialMint,\n        uint40 expiration,\n        uint256 _liqPrice\n    ) external payable returns (address);\n}\n"},{"file_path":"@openzeppelin/contracts/access/Ownable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)\n\npragma solidity ^0.8.20;\n\nimport {Context} from \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * The initial owner is set to the address provided by the deployer. This can\n * later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n    address private _owner;\n\n    /**\n     * @dev The caller account is not authorized to perform an operation.\n     */\n    error OwnableUnauthorizedAccount(address account);\n\n    /**\n     * @dev The owner is not a valid owner account. (eg. `address(0)`)\n     */\n    error OwnableInvalidOwner(address owner);\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.\n     */\n    constructor(address initialOwner) {\n        if (initialOwner == address(0)) {\n            revert OwnableInvalidOwner(address(0));\n        }\n        _transferOwnership(initialOwner);\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        _checkOwner();\n        _;\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        if (owner() != _msgSender()) {\n            revert OwnableUnauthorizedAccount(_msgSender());\n        }\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby disabling any functionality that is only available to the owner.\n     */\n    function renounceOwnership() public virtual onlyOwner {\n        _transferOwnership(address(0));\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Can only be called by the current owner.\n     */\n    function transferOwnership(address newOwner) public virtual onlyOwner {\n        if (newOwner == address(0)) {\n            revert OwnableInvalidOwner(address(0));\n        }\n        _transferOwnership(newOwner);\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Internal function without access restriction.\n     */\n    function _transferOwnership(address newOwner) internal virtual {\n        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n"},{"file_path":"@openzeppelin/contracts/token/ERC20/IERC20.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Interface of the ERC-20 standard as defined in the ERC.\n */\ninterface IERC20 {\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n\n    /**\n     * @dev Returns the value of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the value of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address to, uint256 value) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n     * caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 value) external returns (bool);\n\n    /**\n     * @dev Moves a `value` amount of tokens from `from` to `to` using the\n     * allowance mechanism. `value` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n"},{"file_path":"contracts/interface/IDecentralizedEURO.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IReserve} from \"./IReserve.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\ninterface IDecentralizedEURO is IERC20 {\n    function suggestMinter(\n        address _minter,\n        uint256 _applicationPeriod,\n        uint256 _applicationFee,\n        string calldata _message\n    ) external;\n\n    function registerPosition(address position) external;\n\n    function denyMinter(address minter, address[] calldata helpers, string calldata message) external;\n\n    function reserve() external view returns (IReserve);\n\n    function minterReserve() external view returns (uint256);\n\n    function calculateAssignedReserve(uint256 mintedAmount, uint32 _reservePPM) external view returns (uint256);\n\n    function calculateFreedAmount(uint256 amountExcludingReserve, uint32 _reservePPM) external view returns (uint256);\n\n    function equity() external view returns (uint256);\n\n    function isMinter(address minter) external view returns (bool);\n\n    function getPositionParent(address position) external view returns (address);\n\n    function mint(address target, uint256 amount) external;\n\n    function mintWithReserve(address target, uint256 amount, uint32 reservePPM) external;\n\n    function burn(uint256 amount) external;\n\n    function burnFrom(address target, uint256 amount) external;\n\n    function burnWithoutReserve(uint256 amount, uint32 reservePPM) external;\n\n    function burnFromWithReserve(\n        address payer,\n        uint256 targetTotalBurnAmount,\n        uint32 reservePPM\n    ) external returns (uint256);\n\n    function coverLoss(address source, uint256 amount) external;\n\n    function distributeProfits(address recipient, uint256 amount) external;\n\n    function collectProfits(address source, uint256 _amount) external;\n}\n"},{"file_path":"contracts/interface/ILeadrate.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface ILeadrate {\n   function currentRatePPM() external view returns (uint24);\n   function currentTicks() external view returns (uint64);\n}"},{"file_path":"contracts/interface/IReserve.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\ninterface IReserve is IERC20 {\n    function invest(uint256 amount, uint256 expected) external returns (uint256);\n    function checkQualified(address sender, address[] calldata helpers) external view;\n    function votesDelegated(address sender, address[] calldata helpers) external view returns (uint256);\n    function totalVotes() external view returns (uint256);\n}\n"},{"file_path":"contracts/interface/IWrappedNative.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IWrappedNative {\n    function deposit() external payable;\n    function withdraw(uint256) external;\n}\n"},{"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}