{"file_path":"contracts/swap/UniswapAmplifier.sol","creation_status":"success","source_code":"// SPDX-License-Identifier: MIT\r\n\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../stablecoin/IFrankencoin.sol\";\r\nimport \"./utils/IUniswapV3Pool.sol\";\r\nimport \"../utils/Ownable.sol\";\r\nimport \"../utils/Math.sol\";\r\nimport \"./utils/IUniswapV3MintCallback.sol\";\r\nimport \"../erc20/SafeERC20.sol\";\r\nimport {Clones} from \"@openzeppelin/contracts/proxy/Clones.sol\";\r\n\r\n/**\r\n * @title UniswapAmplifier\r\n *\r\n * Factory contract to create amplified uniswap positions for a hardcoded pool. Amplified positions are positions for which\r\n * the ZCHF part of the trading pair is borrowed from the Frankencoin protocol and only the other token is provided by the owner.\r\n *\r\n * The range of the amplified position must be in a range of roughly 25% around the anchor price when the amplifier was deployed\r\n * (actually -13.93%/+10.52%). Another important parameter is the minimum amount of dollars that must be provided for a given amount\r\n * of borrowed ZCHF. This ensures that the owner is usually better off repaying the borrowed ZCHF than walking away, even if the\r\n * dollar has declined in value.\r\n * \r\n * The parameters must be chosen with care. Exploiting it is easier than one might think. An attacker might manipulate the price\r\n * of the dollar upwards in the uniswap pool to the upper end of the allowed range, initiate a narrow position and immediately\r\n * buy the minted ZCHF at the lowest allowed price (i.e. -9.52% or 1000 TICKS below the anchor in dollar terms), then manipulate\r\n * the pool price back to the market price. Consequently, the amplifier becomes exploitable as soon as the market price falls more\r\n * than about 41% below the anchor price. See exploitableAt() for the exact threshold at the current parameters.\r\n *\r\n **/\r\ncontract UniswapAmplifier {\r\n\r\n    using SafeERC20 for IERC20;\r\n\r\n    uint256 internal constant Q96 = 0x1000000000000000000000000;\r\n\r\n    IUniswapV3Pool public immutable UNISWAP_POOL;\r\n    bool public immutable ZCHF_IS_TOKEN0;\r\n\r\n    IERC20 public immutable USD;\r\n    IERC20 public immutable ZCHF;\r\n    IFrankencoinMinter public immutable ZCHF_MINTER;\r\n\r\n    // Price anchor USD/ZCHF. Must be verified before proposing as minter!\r\n    // A front-runner could have manipulated the pool during the deployment of the contract.\r\n    uint256 public immutable PRICE_ANCHOR_X96; \r\n    int24 public immutable MAX_DOLLAR_APPRECIATION_TICKS = 1000; // about 10% stronger dollar\r\n    int24 public immutable MAX_DOLLAR_DEPRECIATION_TICKS = 1500; // about 14% weaker dollar\r\n\r\n    int24 public immutable MINIMUM_TICK;\r\n    int24 public immutable MAXIMUM_TICK;\r\n\r\n    uint40 public immutable EXPIRATION;\r\n    uint256 public immutable LIMIT;\r\n\r\n    /// @notice The AmplifiedPosition template that all positions are cloned from (EIP-1167 minimal proxies).\r\n    address public immutable positionImplementation;\r\n\r\n    uint256 public totalBorrowed;\r\n\r\n    mapping(address => uint256) public positionCreationDate;\r\n\r\n    error InvalidUniswapPool();\r\n    error AccessDenied();\r\n    error AmplifierExpired();\r\n    error LimitExceeded(uint256 newValue, uint256 limit);\r\n    error PriceChangedTooMuch(uint256 found, uint256 expected);\r\n    error InvalidTick(int24 min, int24 found, int24 max);\r\n    error InsufficientDollarsInRange(uint256 requiredMinimum, uint256 actuallyFoundInProvidedRange);\r\n\r\n    event AmplifiedPositionCreated(address position);\r\n    event Borrowed(uint256 borrowed, uint256 totalBorrowed);\r\n    event Repaid(uint256 amount, uint256 totalBorrowed);\r\n\r\n    /**\r\n     * Constructs the amplifier for the given pool.\r\n     */\r\n    constructor(address uniswapPool_, address zchf_, address zchfMinter_, uint40 expiration, uint256 borrowingLimit) {\r\n        UNISWAP_POOL = IUniswapV3Pool(uniswapPool_);\r\n        ZCHF = IERC20(zchf_);\r\n        ZCHF_MINTER = IFrankencoinMinter(zchfMinter_);\r\n        EXPIRATION = expiration;\r\n        LIMIT = borrowingLimit;\r\n\r\n        (, int24 tick, , , , , ) = UNISWAP_POOL.slot0();\r\n        uint256 price = getPrice();\r\n\r\n        // Slightly asymmetric range in expectation of ZCHF being the stronger currency: allow the dollar to\r\n        // weaken about 14% but only strengthen about 10%. Which tick direction corresponds to a weaker dollar\r\n        // depends on the ordering: if ZCHF is token0 the pool price is USD/ZCHF and a weaker dollar means a\r\n        // higher tick; if ZCHF is token1 the pool price is ZCHF/USD and a weaker dollar means a lower tick.\r\n        ZCHF_IS_TOKEN0 = UNISWAP_POOL.token0() == zchf_;\r\n        if (ZCHF_IS_TOKEN0) {\r\n            USD = IERC20(UNISWAP_POOL.token1());\r\n            PRICE_ANCHOR_X96 = price;\r\n            MINIMUM_TICK = tick - MAX_DOLLAR_APPRECIATION_TICKS;\r\n            MAXIMUM_TICK = tick + MAX_DOLLAR_DEPRECIATION_TICKS;\r\n        } else {\r\n            if (UNISWAP_POOL.token1() != zchf_) revert InvalidUniswapPool();\r\n            USD = IERC20(UNISWAP_POOL.token0());\r\n            PRICE_ANCHOR_X96 = Math.mulDiv(Q96, Q96, price);\r\n            MINIMUM_TICK = tick - MAX_DOLLAR_DEPRECIATION_TICKS;\r\n            MAXIMUM_TICK = tick + MAX_DOLLAR_APPRECIATION_TICKS;\r\n        }\r\n\r\n        // Deploy the position template once. Its immutable AMP is this amplifier, so all clones read the\r\n        // correct amplifier from the template's code while carrying their own owner/ticks in storage.\r\n        positionImplementation = address(new AmplifiedPosition(this));\r\n    }\r\n\r\n    /// @notice Verifies that the provided ticks are within the amplifier's allowed band [MINIMUM_TICK, MAXIMUM_TICK].\r\n    /// @dev The band is asymmetric around the anchor tick (see the constructor), allowing the dollar to weaken about\r\n    ///      14% but only strengthen about 10%. The pool itself enforces that the ticks are aligned to the tick\r\n    ///      spacing, so no rounding is needed here.\r\n    /// @param ticksLow Lower limit of ticks\r\n    /// @param ticksHigh Higher limit of ticks\r\n    function checkTicks(int24 ticksLow, int24 ticksHigh) public view {\r\n        if (ticksLow < MINIMUM_TICK || ticksLow > MAXIMUM_TICK) revert InvalidTick(MINIMUM_TICK, ticksLow, MAXIMUM_TICK);\r\n        if (ticksHigh < MINIMUM_TICK || ticksHigh > MAXIMUM_TICK) revert InvalidTick(MINIMUM_TICK, ticksHigh, MAXIMUM_TICK);\r\n    }\r\n\r\n    /**\r\n     * @notice The dollar price (CHF per USD, 18 decimals) below which the amplifier becomes exploitable.\r\n     * @dev Once the dollar falls below the exploitable price, an attacker can profitably exploit the contract by manipulating\r\n     * the uniswap price to the upper end of the allowed range, create a narrow position, buy the minted ZCHF at a low price in\r\n     * dollar terms, and then manipulate the price back to the market price. For example, if the LIMIT is 10,000,000 ZCHF and \r\n     * the attacker launches the attack slightly below the exploitable price, they might make a profit of 100'000 ZCHF with the\r\n     * amplifier ending up with 9,900,000 CHF worth of USD. Should this ever happen, the Frankencoin community can either hope\r\n     * for the dollar price to recover, at which point it becomes profitable for the attacker to repay the borrowed ZCHF and get\r\n     * the USD back, or they could create a custom new minter that performs an expiredPublicBurn after the expiration\r\n     * with the missing ZCHF coming out of the equity pool.\r\n     */\r\n    function exploitableAt() public view returns (uint256) {\r\n        // Worst case (narrow position at the strong-dollar floor): P* = P_floor + collateral, in USD per ZCHF, where\r\n        // P_floor = anchor / 1.0001^MAX_DOLLAR_APPRECIATION_TICKS and collateral = getMinimumDollars(one ZCHF). Both\r\n        // are derived from the live parameters, so this needs no adjustment if the band or collateral factor change.\r\n        uint256 floorX96 = Math.mulDiv(PRICE_ANCHOR_X96, Q96, pow1_0001(MAX_DOLLAR_APPRECIATION_TICKS)); // anchor / 1.0001^ticks\r\n        uint256 pStarX96 = floorX96 + getMinimumDollars(Q96); // getMinimumDollars(Q96) == collateral factor * anchor, in Q96\r\n        uint256 chfPerUsdX96 = Math.mulDiv(Q96, Q96, pStarX96); // reciprocal: USD priced in ZCHF, base units, Q96\r\n        return Math.mulDiv(chfPerUsdX96, 10 ** USD.decimals(), Q96); // scale to an 18-decimal CHF/USD price\r\n    }\r\n\r\n    /// @notice Computes 1.0001^ticks in Q96 via exponentiation by squaring, for a non-negative tick count.\r\n    function pow1_0001(int24 ticks) internal pure returns (uint256 result) {\r\n        uint256 base = Math.mulDiv(10001, Q96, 10000); // 1.0001 in Q96\r\n        uint256 exponent = uint256(int256(ticks));\r\n        result = Q96; // 1.0 in Q96\r\n        while (exponent > 0) {\r\n            if (exponent & 1 == 1) result = Math.mulDiv(result, base, Q96);\r\n            base = Math.mulDiv(base, base, Q96);\r\n            exponent >>= 1;\r\n        }\r\n    }\r\n\r\n    /// @notice Calculates min. dollars required for the given ZCHF amount based on the price anchor\r\n    /// @param zchfAmount Amount of ZCHF\r\n    /// @return Amount of dollars\r\n    function getMinimumDollars(uint256 zchfAmount) public view returns (uint256) {\r\n        // Multiplying by 4/5 to allow up to 1.25:1 leverage based on the original price. As a result the system only\r\n        // takes a loss if the dollar declines more than about 41% below the anchor (worst case, for a position at the\r\n        // strong-dollar floor of the band) or about 44% for a position minted at the anchor. See exploitableAt().\r\n        return Math.mulDiv(PRICE_ANCHOR_X96, zchfAmount, Q96) * 4 / 5;\r\n    }\r\n\r\n    /// @notice The current pool price, denominated as token1 per token0 in Q96.\r\n    function getPrice() public view returns (uint256) {\r\n        (uint160 sqrtPriceX96, , , , , , ) = UNISWAP_POOL.slot0();\r\n        return Math.mulDiv(sqrtPriceX96, sqrtPriceX96, Q96);\r\n    }\r\n\r\n    /// @notice Slippage guard: reverts unless the expected price is within 0.1% of the live pool price.\r\n    /// @dev With a fixed liquidity amount and range, both token amounts of a mint or burn are a deterministic\r\n    ///      function of the price. Pinning the price to a tight band therefore bounds the amounts on both\r\n    ///      sides at once, protecting mints and burns against sandwiching.\r\n    /// @param expectedPriceX96 Expected pool price (token1 per token0) in Q96, same convention as the constructor.\r\n    function checkPrice(uint256 expectedPriceX96) public view {\r\n        if (expectedPriceX96 > 0) {\r\n            uint256 price = getPrice();\r\n            if ((price * 999) / 1000 > expectedPriceX96 || (price * 1001) / 1000 < expectedPriceX96) {\r\n                revert PriceChangedTooMuch(price, expectedPriceX96);\r\n            }\r\n        }\r\n    }\r\n\r\n    /// @notice Borrows ZCHF into the pool against the owner's dollars.\r\n    /// @dev The position's range must require enough dollars that the owner is usually better off repaying than\r\n    ///      walking away. Check getMinimumDollars for the amount of dollars needed.\r\n    ///      Requires the owner to have approved this contract for the pairing token.\r\n    /// @param owner User to take the pairing tokens from\r\n    /// @param token0Amount Amount of token0 to send to the pool\r\n    /// @param token1Amount Amount of token1 to send to the pool\r\n    /// @return Amount borrowed in ZCHF\r\n    function borrowIntoPool(address owner, uint256 token0Amount, uint256 token1Amount) external onlyPosition returns (uint256) {\r\n        if (block.timestamp > EXPIRATION) revert AmplifierExpired();\r\n\r\n        (uint256 zchfAmount, uint256 collateralAmount) = ZCHF_IS_TOKEN0 ? (token0Amount, token1Amount) : (token1Amount, token0Amount);\r\n        uint256 required = getMinimumDollars(zchfAmount);\r\n        if (collateralAmount < required) revert InsufficientDollarsInRange(required, collateralAmount);\r\n\r\n        USD.safeTransferFrom(owner, address(UNISWAP_POOL), collateralAmount); // obtain the dollars and deposit them into the pool\r\n        ZCHF_MINTER.mint(owner, zchfAmount); // mint to the owner first for better traceability\r\n        ZCHF.transferFrom(owner, address(UNISWAP_POOL), zchfAmount); // transfer to the uniswap pool\r\n\r\n        totalBorrowed += zchfAmount;\r\n        if (totalBorrowed > LIMIT) revert LimitExceeded(totalBorrowed, LIMIT);\r\n\r\n        emit Borrowed(zchfAmount, totalBorrowed);\r\n        return zchfAmount;\r\n    }\r\n\r\n    /// @notice Repays a position by burning borrowed ZCHF from the owner\r\n    /// @param owner ZCHF holder\r\n    /// @param borrowed Total amount of ZCHF borrowed\r\n    /// @param returnedPart Amount of liquidity returned\r\n    /// @param total  Total amount of liquidity held by the position\r\n    /// @return Amount of ZCHF burned from the owner\r\n    function repay(address owner, uint256 borrowed, uint128 returnedPart, uint128 total) external onlyPosition returns (uint256) {\r\n        if (returnedPart > 0) {\r\n            uint256 zchfToReturn = Math.mulDiv(borrowed, returnedPart, total);\r\n            ZCHF_MINTER.burnFrom(owner, zchfToReturn);\r\n            totalBorrowed -= zchfToReturn;\r\n            emit Repaid(zchfToReturn, totalBorrowed);\r\n            return zchfToReturn;\r\n        } else {\r\n            return 0;\r\n        }\r\n    }\r\n\r\n    /// @notice Creates a new amplified position with the msg.sender as owner, bound to the given tick range.\r\n    /// @param tickLow Must be within what checkTicks() allows.\r\n    /// @param tickHigh Must be within what checkTicks() allows.\r\n    /// @return Address of the newly created Position\r\n    function createAmplifiedPosition(int24 tickLow, int24 tickHigh) public returns (address) {\r\n        checkTicks(tickLow, tickHigh);\r\n        address position = Clones.clone(positionImplementation);\r\n        AmplifiedPosition(position).initialize(msg.sender, tickLow, tickHigh);\r\n        positionCreationDate[position] = block.timestamp;\r\n        emit AmplifiedPositionCreated(position);\r\n        return position;\r\n    }\r\n\r\n    modifier onlyPosition() {\r\n        if (positionCreationDate[msg.sender] == 0) revert AccessDenied();\r\n        _;\r\n    }\r\n}\r\n\r\ninterface IFrankencoinMinter {\r\n    function mint(address to, uint256 amount) external;\r\n    function burnFrom(address from, uint256 amount) external;\r\n}\r\n\r\n/**\r\n * An amplified position belonging to a specific owner.\r\n */\r\ncontract AmplifiedPosition is Ownable, IUniswapV3MintCallback {\r\n    // The amplifier is baked into the template's code, so every clone reads the correct amplifier even\r\n    // though it is a minimal proxy delegatecalling into this template.\r\n    UniswapAmplifier immutable AMP;\r\n\r\n    // A position is bound to a single tick range, set once at initialization. Liquidity (L) is only comparable\r\n    // within one range, so aggregating L across different ranges would corrupt the proportional repay accounting.\r\n    // These cannot be immutable because clones carry their own values in storage.\r\n    int24 public tickLow;\r\n    int24 public tickHigh;\r\n\r\n    uint256 public borrowed;\r\n\r\n    error AccessDenied(address sender);\r\n    error NotExpired();\r\n\r\n    event Mint(uint128 liquidityAdded, uint256 token0, uint256 token1, uint256 borrowed);\r\n    event Burn(uint128 liquidityRemoved, uint256 token0, uint256 token1, uint256 repaid);\r\n\r\n    /// @notice Only runs on the template. Clones are created via Clones.clone and configured through initialize.\r\n    constructor(UniswapAmplifier parent) {\r\n        AMP = parent;\r\n    }\r\n\r\n    /// @notice Configures a freshly cloned position. Callable exactly once, and only by the amplifier.\r\n    /// @dev The owner == address(0) check doubles as the re-initialization guard: a fresh clone has no owner yet,\r\n    ///      and _setOwner rejects the zero address, so it can never be initialized twice.\r\n    function initialize(address owner_, int24 tickLow_, int24 tickHigh_) external {\r\n        // `owner` is the Ownable state variable: nonzero means already initialized.\r\n        if (owner != address(0) || msg.sender != address(AMP)) revert AccessDenied(msg.sender);\r\n        tickLow = tickLow_;\r\n        tickHigh = tickHigh_;\r\n        _setOwner(owner_);\r\n    }\r\n\r\n    /// @notice The total liquidity of this position as recorded by the pool.\r\n    /// @dev Read from the pool instead of tracked locally so that liquidity donated to this position\r\n    ///      (minted directly on the pool with this position as recipient) is included and can be burned\r\n    ///      like any other liquidity, repaying a proportional share of the debt.\r\n    function totalLiquidity() public view returns (uint128 liquidity) {\r\n        (liquidity, , , , ) = AMP.UNISWAP_POOL().positions(keccak256(abi.encodePacked(address(this), tickLow, tickHigh)));\r\n    }\r\n\r\n    /// @notice Mints the provided amount of liquidity into this position's range.\r\n    /// @dev This function only succeeds if the caller has sufficient dollars on his address and if there is an allowance in place.\r\n    /// @param amount Amount of liquidity to add\r\n    /// @param expectedPriceX96 Expected pool price (token1/token0, Q96); reverts if the expected price is not within 0.1% (slippage guard) of the pool price.\r\n    /// Set expectedPriceX96 to 0 to skip the slippage guard.\r\n    function mint(uint128 amount, uint256 expectedPriceX96) external onlyOwner {\r\n        AMP.checkPrice(expectedPriceX96);\r\n        uint256 previouslyBorrowed = borrowed;\r\n        (uint256 amount0, uint256 amount1) = AMP.UNISWAP_POOL().mint(address(this), tickLow, tickHigh, amount, \"\");\r\n        emit Mint(amount, amount0, amount1, borrowed - previouslyBorrowed);\r\n    }\r\n\r\n    /// @notice Callback from pool to provide the indicated token amounts.\r\n    /// @param amount0Owed Amount of token0 owed to the pool\r\n    /// @param amount1Owed Amount of token1 owed to the pool\r\n    function uniswapV3MintCallback(uint256 amount0Owed, uint256 amount1Owed, bytes calldata) external {\r\n        if (msg.sender != address(AMP.UNISWAP_POOL())) revert AccessDenied(msg.sender); // we can take this shortcut as we know the pool\r\n        borrowed += AMP.borrowIntoPool(owner, amount0Owed, amount1Owed); // obtain the tokens and deposit them into the pool\r\n    }\r\n\r\n    /// @notice Return the provided amount of liquidity.\r\n    /// @dev The tokens will be returned to the owner. In case additional ZCHF are required to repay the borrowed amounts, the missing\r\n    ///      ZCHF are taken from the owner's address. When burning X% of the position liquidity, X% of the borrowed Frankencoins must be returned.\r\n    ///      At the same time, accrued fees are collected.\r\n    /// @param burnedLiquidity Liquidity to burn\r\n    /// @param expectedPriceX96 Expected pool price (token1/token0, Q96); reverts if the expected price is not within 0.1% (slippage guard) of the pool price.\r\n    /// @return amounts of token0 and token1 returned\r\n    function burn(uint128 burnedLiquidity, uint256 expectedPriceX96) external onlyOwner returns (uint256, uint256) {\r\n        return _burn(burnedLiquidity, expectedPriceX96);\r\n    }\r\n\r\n    /// @notice Once the amplifier has expired, let anyone burn positions and collect the underlying tokens.\r\n    /// @dev As long as the market price of the dollar has not declined too much below the anchor price (depending\r\n    ///      on where the position's range sits within the allowed band), this can be called profitably at the\r\n    ///      expense of the position owner. Beyond that threshold, winding down is unprofitable and the debt\r\n    ///      may remain unpaid.\r\n    ///      For the test amplifier, we intentionally let a position expire. It took nine days for a bot to pick up the\r\n    ///      free money in transaction 0x9b188d16802794f83370c30f2705b7d5de2e9226f8117519060403239465584d.\r\n    /// @param burnedLiquidity Liquidity to burn\r\n    /// @param expectedPriceX96 Expected pool price (token1/token0, Q96); reverts if the expected price is not within 0.1% (slippage guard) of the pool price.\r\n    /// @return amounts of token0 and token1 returned\r\n    function expiredPublicBurn(uint128 burnedLiquidity, uint256 expectedPriceX96) external returns (uint256, uint256) {\r\n        if (block.timestamp <= AMP.EXPIRATION()) revert NotExpired();\r\n        return _burn(burnedLiquidity, expectedPriceX96);\r\n    }\r\n\r\n    function _burn(uint128 burnedLiquidity, uint256 expectedPriceX96) internal returns (uint256, uint256) {\r\n        AMP.checkPrice(expectedPriceX96);\r\n        uint128 total = totalLiquidity(); // must be read before pool.burn reduces it\r\n        IUniswapV3Pool pool = AMP.UNISWAP_POOL();\r\n        pool.burn(tickLow, tickHigh, burnedLiquidity); // burn does not collect yet, also ensures burnedLiquidity <= total\r\n        (uint128 amount0, uint128 amount1) = pool.collect(msg.sender, tickLow, tickHigh, type(uint128).max, type(uint128).max); // collect principal + fees\r\n        uint256 returnedZCHF = AMP.repay(msg.sender, borrowed, burnedLiquidity, total);\r\n        borrowed -= returnedZCHF;\r\n        emit Burn(burnedLiquidity, amount0, amount1, returnedZCHF);\r\n        return (amount0, amount1);\r\n    }\r\n}\r\n","deployed_bytecode":"0x608060405234801561001057600080fd5b506004361061014d5760003560e01c80637e8d54fa116100c3578063bb4b57341161007c578063bb4b573414610386578063d2091e57146103c3578063d267849c146103d6578063d97e1474146103e9578063e2ab4cd714610410578063e5a13f8e1461043757600080fd5b80637e8d54fa146102d35780638aa73a88146102e657806398d5fdca1461031d578063a65a4d5814610325578063a92a35381461034c578063af8214ef1461035f57600080fd5b80631de7463a116101155780631de7463a1461024c5780631e6e26e3146102615780634c19386c146102745780635c6509551461027d5780636f8df6ac1461028557806371add723146102ac57600080fd5b80631836e0da1461015257806318f20c4d146101965780631bf6c21b146101c45780631d3e8dc3146101eb5780631d61057714610225575b600080fd5b6101797f000000000000000000000000b58e61c3098d85632df34eecfb899a1ed80921cb81565b6040516001600160a01b0390911681526020015b60405180910390f35b6101b66101a43660046110e4565b60016020526000908152604090205481565b60405190815260200161018d565b6101797f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec781565b6102127f00000000000000000000000000000000000000000000000000000000000003e881565b60405160029190910b815260200161018d565b6101797f0000000000000000000000008e4318e2cb1ae291254b187001a59a1f8ac78cef81565b61025f61025a366004611101565b61045e565b005b61017961026f366004611129565b6104df565b6101b660005481565b6101b66105dc565b6102127ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbcd7f81565b6102127f00000000000000000000000000000000000000000000000000000000000005dc81565b6101b66102e1366004611179565b610709565b61030d7f000000000000000000000000000000000000000000000000000000000000000181565b604051901515815260200161018d565b6101b6610853565b6101797f000000000000000000000000b58e61c3098d85632df34eecfb899a1ed80921cb81565b6101b661035a3660046111c8565b610907565b6101b67f000000000000000000000000000000000000000000021165458500521280000081565b6103ad7f000000000000000000000000000000000000000000000000000000006bad937f81565b60405164ffffffffff909116815260200161018d565b6101b66103d1366004611101565b610c4e565b61025f6103e4366004611129565b610c96565b6101797f0000000000000000000000008746159d385f84cb550ab5ae015c0ddf6909b8f281565b6101b67f00000000000000000000000000000000000000000000000001608a78930979be81565b6102127ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbd74381565b80156104dc57600061046e610853565b9050816103e8610480836103e7611213565b61048a9190611240565b11806104ad5750816103e86104a1836103e9611213565b6104ab9190611240565b105b156104da57604051631472e7a960e21b815260048101829052602481018390526044015b60405180910390fd5b505b50565b60006104eb8383610c96565b60006105167f0000000000000000000000008746159d385f84cb550ab5ae015c0ddf6909b8f2610e32565b6040516378b7b58560e11b8152336004820152600286810b602483015285900b60448201529091506001600160a01b0382169063f16f6b0a90606401600060405180830381600087803b15801561056c57600080fd5b505af1158015610580573d6000803e3d6000fd5b505050506001600160a01b03811660008181526001602090815260409182902042905590519182527f31baf664974ca477fc3db2ef7a5c189c5bd2a8b26c2d3474a6c0746a25ccd296910160405180910390a190505b92915050565b6000806106367f00000000000000000000000000000000000000000000000001608a78930979be600160601b6106317f00000000000000000000000000000000000000000000000000000000000003e8610ecf565b610f37565b90506000610647600160601b610c4e565b6106519083611262565b90506000610664600160601b8084610f37565b9050610701817f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec76001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156106c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106ec9190611286565b6106f790600a611385565b600160601b610f37565b935050505090565b33600090815260016020526040812054810361073857604051634ca8886760e01b815260040160405180910390fd5b6001600160801b0383161561084757600061076685856001600160801b0316856001600160801b0316610f37565b60405163079cc67960e41b81526001600160a01b038881166004830152602482018390529192507f000000000000000000000000b58e61c3098d85632df34eecfb899a1ed80921cb909116906379cc679090604401600060405180830381600087803b1580156107d557600080fd5b505af11580156107e9573d6000803e3d6000fd5b50505050806000808282546107fe9190611394565b90915550506000546040805183815260208101929092527f81472a96709c8315c82af40d41ef624a642ad53864b097e53af675593bb4e035910160405180910390a1905061084b565b5060005b949350505050565b6000807f0000000000000000000000008e4318e2cb1ae291254b187001a59a1f8ac78cef6001600160a01b0316633850c7bd6040518163ffffffff1660e01b815260040160e060405180830381865afa1580156108b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d891906113c9565b5050505050509050610901816001600160a01b0316826001600160a01b0316600160601b610f37565b91505090565b33600090815260016020526040812054810361093657604051634ca8886760e01b815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000006bad937f64ffffffffff1642111561097e57604051631bc5d7a960e01b815260040160405180910390fd5b6000807f00000000000000000000000000000000000000000000000000000000000000016109ad5783856109b0565b84845b9150915060006109bf83610c4e565b9050808210156109eb57604051626cca5160e01b815260048101829052602481018390526044016104d1565b610a406001600160a01b037f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec716887f0000000000000000000000008e4318e2cb1ae291254b187001a59a1f8ac78cef85611021565b6040516340c10f1960e01b81526001600160a01b038881166004830152602482018590527f000000000000000000000000b58e61c3098d85632df34eecfb899a1ed80921cb16906340c10f1990604401600060405180830381600087803b158015610aaa57600080fd5b505af1158015610abe573d6000803e3d6000fd5b50506040516323b872dd60e01b81526001600160a01b038a811660048301527f0000000000000000000000008e4318e2cb1ae291254b187001a59a1f8ac78cef81166024830152604482018790527f000000000000000000000000b58e61c3098d85632df34eecfb899a1ed80921cb1692506323b872dd91506064016020604051808303816000875af1158015610b59573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b7d9190611454565b5082600080828254610b8f9190611262565b90915550506000547f00000000000000000000000000000000000000000002116545850052128000001015610c0457600054604051634779077960e11b815260048101919091527f000000000000000000000000000000000000000000021165458500521280000060248201526044016104d1565b6000546040805185815260208101929092527f14a13f958d7fe38fb8529e8d43353b6d9120f52444e486a4077f68a3fc77dcbf910160405180910390a150909150505b9392505050565b60006005610c817f00000000000000000000000000000000000000000000000001608a78930979be84600160601b610f37565b610c8c906004611213565b6105d69190611240565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbcd7f60020b8260020b1280610cef57507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbd74360020b8260020b135b15610d64576040516317c8eaa560e11b81527ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbcd7f600290810b600483015283810b60248301527ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbd743900b60448201526064016104d1565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbcd7f60020b8160020b1280610dbd57507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbd74360020b8160020b135b156104da576040516317c8eaa560e11b81527ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbcd7f600290810b600483015282810b60248301527ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbd743900b60448201526064016104d1565b6000604051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b81528260601b60148201526e5af43d82803e903d91602b57fd5bf360881b60288201526037816000f09150506001600160a01b038116610eca5760405162461bcd60e51b8152602060048201526016602482015275115490cc4c4d8dce8818dc99585d194819985a5b195960521b60448201526064016104d1565b919050565b600080610ee5612711600160601b612710610f37565b600160601b92509050600283900b5b8015610f305780600116600103610f1757610f148383600160601b610f37565b92505b610f268283600160601b610f37565b915060011c610ef4565b5050919050565b6000808060001985870985870292508281108382030391505080600003610f7157838281610f6757610f6761122a565b0492505050610c47565b808411610fb85760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b60448201526064016104d1565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b61102f84848484600161105d565b61105757604051635274afe760e01b81526001600160a01b03851660048201526024016104d1565b50505050565b6040516323b872dd60e01b60008181526001600160a01b038781166004528616602452604485905291602083606481808c5af1925060016000511483166110bd5783831516156110b0573d6000823e3d81fd5b6000883b113d1516831692505b60405250600060605295945050505050565b6001600160a01b03811681146104dc57600080fd5b6000602082840312156110f657600080fd5b8135610c47816110cf565b60006020828403121561111357600080fd5b5035919050565b8060020b81146104dc57600080fd5b6000806040838503121561113c57600080fd5b82356111478161111a565b915060208301356111578161111a565b809150509250929050565b80356001600160801b0381168114610eca57600080fd5b6000806000806080858703121561118f57600080fd5b843561119a816110cf565b9350602085013592506111af60408601611162565b91506111bd60608601611162565b905092959194509250565b6000806000606084860312156111dd57600080fd5b83356111e8816110cf565b95602085013595506040909401359392505050565b634e487b7160e01b600052601160045260246000fd5b80820281158282048414176105d6576105d66111fd565b634e487b7160e01b600052601260045260246000fd5b60008261125d57634e487b7160e01b600052601260045260246000fd5b500490565b808201808211156105d6576105d66111fd565b805160ff81168114610eca57600080fd5b60006020828403121561129857600080fd5b610c4782611275565b600181815b808511156112dc5781600019048211156112c2576112c26111fd565b808516156112cf57918102915b93841c93908002906112a6565b509250929050565b6000826112f3575060016105d6565b81611300575060006105d6565b816001811461131657600281146113205761133c565b60019150506105d6565b60ff841115611331576113316111fd565b50506001821b6105d6565b5060208310610133831016604e8410600b841016171561135f575081810a6105d6565b61136983836112a1565b806000190482111561137d5761137d6111fd565b029392505050565b6000610c4760ff8416836112e4565b818103818111156105d6576105d66111fd565b805161ffff81168114610eca57600080fd5b80518015158114610eca57600080fd5b600080600080600080600060e0888a0312156113e457600080fd5b87516113ef816110cf565b60208901519097506114008161111a565b955061140e604089016113a7565b945061141c606089016113a7565b935061142a608089016113a7565b925061143860a08901611275565b915061144660c089016113b9565b905092959891949750929550565b60006020828403121561146657600080fd5b610c47826113b956fea264697066735822122053e1b48d50a22de4eff2d904fdc153f690b86ee082dd5a526d068efbb18ad27d64736f6c63430008180033","optimization_enabled":true,"verified_twin_address_hash":null,"is_verified":true,"compiler_settings":{"evmVersion":"paris","libraries":{},"metadata":{"useLiteralContent":true},"optimizer":{"enabled":true,"runs":200},"outputSelection":{"*":{"":["*"],"*":["*"]}}},"optimization_runs":200,"sourcify_repo_url":null,"decoded_constructor_args":[["0x8E4318E2cb1ae291254B187001a59a1f8ac78cEF",{"internalType":"address","name":"uniswapPool_","type":"address"}],["0xB58E61C3098d85632Df34EecfB899A1Ed80921cB",{"internalType":"address","name":"zchf_","type":"address"}],["0xB58E61C3098d85632Df34EecfB899A1Ed80921cB",{"internalType":"address","name":"zchfMinter_","type":"address"}],["1806537599",{"internalType":"uint40","name":"expiration","type":"uint40"}],["2500000000000000000000000",{"internalType":"uint256","name":"borrowingLimit","type":"uint256"}]],"compiler_version":"v0.8.24+commit.e11b9ed9","is_verified_via_verifier_alliance":false,"verified_at":"2026-08-20T11:24:41.549850Z","implementations":[],"proxy_type":null,"external_libraries":[],"creation_bytecode":"0x6102206040526103e8610140526105dc610160523480156200002057600080fd5b5060405162002d9938038062002d998339810160408190526200004391620005a7565b6001600160a01b03808616608081905285821660e09081529185166101005264ffffffffff84166101c0526101e083905260408051633850c7bd60e01b81529051600093633850c7bd92600480820193918290030181865afa158015620000ae573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000d491906200063c565b50505050509150506000620000ee620003d460201b60201c565b9050856001600160a01b03166080516001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200013b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001619190620006ec565b6001600160a01b03161460a08190521562000223576080516001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa158015620001b7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001dd9190620006ec565b6001600160a01b031660c05261012081905261014051620001ff908362000722565b60020b610180526101605162000216908362000750565b60020b6101a0526200037c565b856001600160a01b03166080516001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200026e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002949190620006ec565b6001600160a01b031614620002bc576040516312a5c13d60e31b815260040160405180910390fd5b6080516001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015620002fd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620003239190620006ec565b6001600160a01b031660c052620003496c0100000000000000000000000080836200047e565b61012052610160516200035d908362000722565b60020b610180526101405162000374908362000750565b60020b6101a0525b306040516200038b9062000580565b6001600160a01b039091168152602001604051809103906000f080158015620003b8573d6000803e3d6000fd5b506001600160a01b031661020052506200078e95505050505050565b6000806080516001600160a01b0316633850c7bd6040518163ffffffff1660e01b815260040160e060405180830381865afa15801562000418573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200043e91906200063c565b505050505050905062000478816001600160a01b0316826001600160a01b03166c010000000000000000000000006200047e60201b60201c565b91505090565b6000808060001985870985870292508281108382030391505080600003620004bd57838281620004b257620004b262000778565b049250505062000579565b808411620005115760405162461bcd60e51b815260206004820152601560248201527f4d6174683a206d756c446976206f766572666c6f770000000000000000000000604482015260640160405180910390fd5b600084868809851960019081018716968790049682860381900495909211909303600082900391909104909201919091029190911760038402600290811880860282030280860282030280860282030280860282030280860282030280860290910302029150505b9392505050565b6110218062001d7883390190565b6001600160a01b0381168114620005a457600080fd5b50565b600080600080600060a08688031215620005c057600080fd5b8551620005cd816200058e565b6020870151909550620005e0816200058e565b6040870151909450620005f3816200058e565b606087015190935064ffffffffff811681146200060f57600080fd5b80925050608086015190509295509295909350565b805161ffff811681146200063757600080fd5b919050565b600080600080600080600060e0888a0312156200065857600080fd5b875162000665816200058e565b8097505060208801518060020b81146200067e57600080fd5b95506200068e6040890162000624565b94506200069e6060890162000624565b9350620006ae6080890162000624565b925060a088015160ff81168114620006c557600080fd5b60c08901519092508015158114620006dc57600080fd5b8091505092959891949750929550565b600060208284031215620006ff57600080fd5b815162000579816200058e565b634e487b7160e01b600052601160045260246000fd5b600282810b9082900b03627fffff198112627fffff821317156200074a576200074a6200070c565b92915050565b600281810b9083900b01627fffff8113627fffff19821217156200074a576200074a6200070c565b634e487b7160e01b600052601260045260246000fd5b60805160a05160c05160e05161010051610120516101405161016051610180516101a0516101c0516101e051610200516114a5620008d3600039600081816103ee01526104f201526000818161036401528181610b990152610bd801526000818161038b015261093801526000818161043c01528181610cc701528181610d3601528181610d950152610e0401526000818161028a01528181610c9801528181610d0301528181610d660152610dd1015260006102b10152600081816101f0015261060d015260008181610415015281816105e40152610c5701526000818161032a0152818161078f0152610a660152600081816101570152610b0e0152600081816101c90152818161066c01526109f80152600081816102eb015261098301526000818161022a0152818161085801528181610a1b0152610adf01526114a56000f3fe608060405234801561001057600080fd5b506004361061014d5760003560e01c80637e8d54fa116100c3578063bb4b57341161007c578063bb4b573414610386578063d2091e57146103c3578063d267849c146103d6578063d97e1474146103e9578063e2ab4cd714610410578063e5a13f8e1461043757600080fd5b80637e8d54fa146102d35780638aa73a88146102e657806398d5fdca1461031d578063a65a4d5814610325578063a92a35381461034c578063af8214ef1461035f57600080fd5b80631de7463a116101155780631de7463a1461024c5780631e6e26e3146102615780634c19386c146102745780635c6509551461027d5780636f8df6ac1461028557806371add723146102ac57600080fd5b80631836e0da1461015257806318f20c4d146101965780631bf6c21b146101c45780631d3e8dc3146101eb5780631d61057714610225575b600080fd5b6101797f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b6101b66101a43660046110e4565b60016020526000908152604090205481565b60405190815260200161018d565b6101797f000000000000000000000000000000000000000000000000000000000000000081565b6102127f000000000000000000000000000000000000000000000000000000000000000081565b60405160029190910b815260200161018d565b6101797f000000000000000000000000000000000000000000000000000000000000000081565b61025f61025a366004611101565b61045e565b005b61017961026f366004611129565b6104df565b6101b660005481565b6101b66105dc565b6102127f000000000000000000000000000000000000000000000000000000000000000081565b6102127f000000000000000000000000000000000000000000000000000000000000000081565b6101b66102e1366004611179565b610709565b61030d7f000000000000000000000000000000000000000000000000000000000000000081565b604051901515815260200161018d565b6101b6610853565b6101797f000000000000000000000000000000000000000000000000000000000000000081565b6101b661035a3660046111c8565b610907565b6101b67f000000000000000000000000000000000000000000000000000000000000000081565b6103ad7f000000000000000000000000000000000000000000000000000000000000000081565b60405164ffffffffff909116815260200161018d565b6101b66103d1366004611101565b610c4e565b61025f6103e4366004611129565b610c96565b6101797f000000000000000000000000000000000000000000000000000000000000000081565b6101b67f000000000000000000000000000000000000000000000000000000000000000081565b6102127f000000000000000000000000000000000000000000000000000000000000000081565b80156104dc57600061046e610853565b9050816103e8610480836103e7611213565b61048a9190611240565b11806104ad5750816103e86104a1836103e9611213565b6104ab9190611240565b105b156104da57604051631472e7a960e21b815260048101829052602481018390526044015b60405180910390fd5b505b50565b60006104eb8383610c96565b60006105167f0000000000000000000000000000000000000000000000000000000000000000610e32565b6040516378b7b58560e11b8152336004820152600286810b602483015285900b60448201529091506001600160a01b0382169063f16f6b0a90606401600060405180830381600087803b15801561056c57600080fd5b505af1158015610580573d6000803e3d6000fd5b505050506001600160a01b03811660008181526001602090815260409182902042905590519182527f31baf664974ca477fc3db2ef7a5c189c5bd2a8b26c2d3474a6c0746a25ccd296910160405180910390a190505b92915050565b6000806106367f0000000000000000000000000000000000000000000000000000000000000000600160601b6106317f0000000000000000000000000000000000000000000000000000000000000000610ecf565b610f37565b90506000610647600160601b610c4e565b6106519083611262565b90506000610664600160601b8084610f37565b9050610701817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156106c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106ec9190611286565b6106f790600a611385565b600160601b610f37565b935050505090565b33600090815260016020526040812054810361073857604051634ca8886760e01b815260040160405180910390fd5b6001600160801b0383161561084757600061076685856001600160801b0316856001600160801b0316610f37565b60405163079cc67960e41b81526001600160a01b038881166004830152602482018390529192507f0000000000000000000000000000000000000000000000000000000000000000909116906379cc679090604401600060405180830381600087803b1580156107d557600080fd5b505af11580156107e9573d6000803e3d6000fd5b50505050806000808282546107fe9190611394565b90915550506000546040805183815260208101929092527f81472a96709c8315c82af40d41ef624a642ad53864b097e53af675593bb4e035910160405180910390a1905061084b565b5060005b949350505050565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633850c7bd6040518163ffffffff1660e01b815260040160e060405180830381865afa1580156108b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d891906113c9565b5050505050509050610901816001600160a01b0316826001600160a01b0316600160601b610f37565b91505090565b33600090815260016020526040812054810361093657604051634ca8886760e01b815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000064ffffffffff1642111561097e57604051631bc5d7a960e01b815260040160405180910390fd5b6000807f00000000000000000000000000000000000000000000000000000000000000006109ad5783856109b0565b84845b9150915060006109bf83610c4e565b9050808210156109eb57604051626cca5160e01b815260048101829052602481018390526044016104d1565b610a406001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016887f000000000000000000000000000000000000000000000000000000000000000085611021565b6040516340c10f1960e01b81526001600160a01b038881166004830152602482018590527f000000000000000000000000000000000000000000000000000000000000000016906340c10f1990604401600060405180830381600087803b158015610aaa57600080fd5b505af1158015610abe573d6000803e3d6000fd5b50506040516323b872dd60e01b81526001600160a01b038a811660048301527f000000000000000000000000000000000000000000000000000000000000000081166024830152604482018790527f00000000000000000000000000000000000000000000000000000000000000001692506323b872dd91506064016020604051808303816000875af1158015610b59573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b7d9190611454565b5082600080828254610b8f9190611262565b90915550506000547f00000000000000000000000000000000000000000000000000000000000000001015610c0457600054604051634779077960e11b815260048101919091527f000000000000000000000000000000000000000000000000000000000000000060248201526044016104d1565b6000546040805185815260208101929092527f14a13f958d7fe38fb8529e8d43353b6d9120f52444e486a4077f68a3fc77dcbf910160405180910390a150909150505b9392505050565b60006005610c817f000000000000000000000000000000000000000000000000000000000000000084600160601b610f37565b610c8c906004611213565b6105d69190611240565b7f000000000000000000000000000000000000000000000000000000000000000060020b8260020b1280610cef57507f000000000000000000000000000000000000000000000000000000000000000060020b8260020b135b15610d64576040516317c8eaa560e11b81527f0000000000000000000000000000000000000000000000000000000000000000600290810b600483015283810b60248301527f0000000000000000000000000000000000000000000000000000000000000000900b60448201526064016104d1565b7f000000000000000000000000000000000000000000000000000000000000000060020b8160020b1280610dbd57507f000000000000000000000000000000000000000000000000000000000000000060020b8160020b135b156104da576040516317c8eaa560e11b81527f0000000000000000000000000000000000000000000000000000000000000000600290810b600483015282810b60248301527f0000000000000000000000000000000000000000000000000000000000000000900b60448201526064016104d1565b6000604051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b81528260601b60148201526e5af43d82803e903d91602b57fd5bf360881b60288201526037816000f09150506001600160a01b038116610eca5760405162461bcd60e51b8152602060048201526016602482015275115490cc4c4d8dce8818dc99585d194819985a5b195960521b60448201526064016104d1565b919050565b600080610ee5612711600160601b612710610f37565b600160601b92509050600283900b5b8015610f305780600116600103610f1757610f148383600160601b610f37565b92505b610f268283600160601b610f37565b915060011c610ef4565b5050919050565b6000808060001985870985870292508281108382030391505080600003610f7157838281610f6757610f6761122a565b0492505050610c47565b808411610fb85760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b60448201526064016104d1565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b61102f84848484600161105d565b61105757604051635274afe760e01b81526001600160a01b03851660048201526024016104d1565b50505050565b6040516323b872dd60e01b60008181526001600160a01b038781166004528616602452604485905291602083606481808c5af1925060016000511483166110bd5783831516156110b0573d6000823e3d81fd5b6000883b113d1516831692505b60405250600060605295945050505050565b6001600160a01b03811681146104dc57600080fd5b6000602082840312156110f657600080fd5b8135610c47816110cf565b60006020828403121561111357600080fd5b5035919050565b8060020b81146104dc57600080fd5b6000806040838503121561113c57600080fd5b82356111478161111a565b915060208301356111578161111a565b809150509250929050565b80356001600160801b0381168114610eca57600080fd5b6000806000806080858703121561118f57600080fd5b843561119a816110cf565b9350602085013592506111af60408601611162565b91506111bd60608601611162565b905092959194509250565b6000806000606084860312156111dd57600080fd5b83356111e8816110cf565b95602085013595506040909401359392505050565b634e487b7160e01b600052601160045260246000fd5b80820281158282048414176105d6576105d66111fd565b634e487b7160e01b600052601260045260246000fd5b60008261125d57634e487b7160e01b600052601260045260246000fd5b500490565b808201808211156105d6576105d66111fd565b805160ff81168114610eca57600080fd5b60006020828403121561129857600080fd5b610c4782611275565b600181815b808511156112dc5781600019048211156112c2576112c26111fd565b808516156112cf57918102915b93841c93908002906112a6565b509250929050565b6000826112f3575060016105d6565b81611300575060006105d6565b816001811461131657600281146113205761133c565b60019150506105d6565b60ff841115611331576113316111fd565b50506001821b6105d6565b5060208310610133831016604e8410600b841016171561135f575081810a6105d6565b61136983836112a1565b806000190482111561137d5761137d6111fd565b029392505050565b6000610c4760ff8416836112e4565b818103818111156105d6576105d66111fd565b805161ffff81168114610eca57600080fd5b80518015158114610eca57600080fd5b600080600080600080600060e0888a0312156113e457600080fd5b87516113ef816110cf565b60208901519097506114008161111a565b955061140e604089016113a7565b945061141c606089016113a7565b935061142a608089016113a7565b925061143860a08901611275565b915061144660c089016113b9565b905092959891949750929550565b60006020828403121561146657600080fd5b610c47826113b956fea264697066735822122053e1b48d50a22de4eff2d904fdc153f690b86ee082dd5a526d068efbb18ad27d64736f6c6343000818003360a060405234801561001057600080fd5b5060405161102138038061102183398101604081905261002f91610040565b6001600160a01b0316608052610070565b60006020828403121561005257600080fd5b81516001600160a01b038116811461006957600080fd5b9392505050565b608051610f576100ca600039600081816101dd01528181610336015281816104100152818161047e015281816106240152818161070c015281816107b60152818161087a015281816108e40152610aea0152610f576000f3fe608060405234801561001057600080fd5b50600436106100a95760003560e01c80638da5cb5b116100715780638da5cb5b1461014e578063b08370a414610179578063d34879971461018c578063e88971e41461019f578063f16f6b0a146101b3578063f2fde38b146101c657600080fd5b806315770f92146100ae57806354e87234146100d357806361c953c1146100fa57806369609c4214610122578063713df1db14610139575b600080fd5b6100b66101d9565b6040516001600160801b0390911681526020015b60405180910390f35b6000546100e790600160a01b900460020b81565b60405160029190910b81526020016100ca565b61010d610108366004610c81565b610331565b604080519283526020830191909152016100ca565b61012b60015481565b6040519081526020016100ca565b61014c610147366004610c81565b6103f1565b005b600054610161906001600160a01b031681565b6040516001600160a01b0390911681526020016100ca565b61010d610187366004610c81565b610616565b61014c61019a366004610cad565b610622565b6000546100e790600160b81b900460020b81565b61014c6101c1366004610d59565b610797565b61014c6101d4366004610d9e565b610842565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316631d6105776040518163ffffffff1660e01b8152600401602060405180830381865afa158015610239573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061025d9190610dc2565b6000546040516bffffffffffffffffffffffff193060601b166020820152600160a01b820460e890811b6034830152600160b81b90920490911b60378201526001600160a01b03919091169063514ea4bf90603a01604051602081830303815290604052805190602001206040518263ffffffff1660e01b81526004016102e691815260200190565b60a060405180830381865afa158015610303573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103279190610ddf565b5092949350505050565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663bb4b57346040518163ffffffff1660e01b8152600401602060405180830381865afa158015610392573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103b69190610e41565b64ffffffffff1642116103dc5760405163d0404f8560e01b815260040160405180910390fd5b6103e68484610857565b915091509250929050565b6103fa33610bdb565b604051630ef3a31d60e11b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690631de7463a9060240160006040518083038186803b15801561045a57600080fd5b505afa15801561046e573d6000803e3d6000fd5b50505050600060015490506000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316631d6105776040518163ffffffff1660e01b8152600401602060405180830381865afa1580156104da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104fe9190610dc2565b60008054604051633c8a7d8d60e01b8152306004820152600160a01b8204600290810b6024830152600160b81b90920490910b60448201526001600160801b038816606482015260a0608482015260a48101919091526001600160a01b039190911690633c8a7d8d9060c40160408051808303816000875af1158015610588573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105ac9190610e68565b915091507f656a4d853090fd2c0ca583f99db3025d8b436246d8043da26f59bbb83ac484fa858383866001546105e29190610ea2565b604080516001600160801b039095168552602085019390935291830152606082015260800160405180910390a15050505050565b6000806103dc33610bdb565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316631d6105776040518163ffffffff1660e01b8152600401602060405180830381865afa158015610680573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106a49190610dc2565b6001600160a01b0316336001600160a01b0316146106dc57604051630504a20d60e01b81523360048201526024015b60405180910390fd5b60005460405163152546a760e31b81526001600160a01b03918216600482015260248101869052604481018590527f00000000000000000000000000000000000000000000000000000000000000009091169063a92a3538906064016020604051808303816000875af1158015610757573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061077b9190610ebb565b6001600082825461078c9190610ed4565b909155505050505050565b6000546001600160a01b03161515806107d95750336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614155b156107f957604051630504a20d60e01b81523360048201526024016106d3565b6000805462ffffff838116600160b81b0262ffffff60b81b19918616600160a01b029190911665ffffffffffff60a01b199092169190911717905561083d83610c09565b505050565b61084b33610bdb565b61085481610c09565b50565b604051630ef3a31d60e11b81526004810182905260009081906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690631de7463a9060240160006040518083038186803b1580156108bc57600080fd5b505afa1580156108d0573d6000803e3d6000fd5b5050505060006108de6101d9565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316631d6105776040518163ffffffff1660e01b8152600401602060405180830381865afa158015610940573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109649190610dc2565b60005460405163a34123a760e01b8152600160a01b8204600290810b6004830152600160b81b90920490910b60248201526001600160801b03881660448201529091506001600160a01b0382169063a34123a79060640160408051808303816000875af11580156109d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109fd9190610e68565b5050600080546040516309e3d67b60e31b8152336004820152600160a01b8204600290810b6024830152600160b81b90920490910b60448201526001600160801b0360648201819052608482015281906001600160a01b03841690634f1eb3d89060a40160408051808303816000875af1158015610a7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aa39190610ee7565b600154604051633f46aa7d60e11b815233600482015260248101919091526001600160801b03808c1660448301528716606482015291935091506000906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690637e8d54fa906084016020604051808303816000875af1158015610b33573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b579190610ebb565b90508060016000828254610b6b9190610ea2565b9091555050604080516001600160801b038b8116825285811660208301528416818301526060810183905290517f32f081b82da9f73738b9f5ce88f7726222ab9a3d175847e7a33c546ac2f0ef9f9181900360800190a1506001600160801b039182169891169650945050505050565b6000546001600160a01b03828116911614610854576040516330cd747160e01b815260040160405180910390fd5b6001600160a01b038116610c1c57600080fd5b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160801b038116811461085457600080fd5b60008060408385031215610c9457600080fd5b8235610c9f81610c6c565b946020939093013593505050565b60008060008060608587031215610cc357600080fd5b8435935060208501359250604085013567ffffffffffffffff80821115610ce957600080fd5b818701915087601f830112610cfd57600080fd5b813581811115610d0c57600080fd5b886020828501011115610d1e57600080fd5b95989497505060200194505050565b6001600160a01b038116811461085457600080fd5b8035600281900b8114610d5457600080fd5b919050565b600080600060608486031215610d6e57600080fd5b8335610d7981610d2d565b9250610d8760208501610d42565b9150610d9560408501610d42565b90509250925092565b600060208284031215610db057600080fd5b8135610dbb81610d2d565b9392505050565b600060208284031215610dd457600080fd5b8151610dbb81610d2d565b600080600080600060a08688031215610df757600080fd5b8551610e0281610c6c565b8095505060208601519350604086015192506060860151610e2281610c6c565b6080870151909250610e3381610c6c565b809150509295509295909350565b600060208284031215610e5357600080fd5b815164ffffffffff81168114610dbb57600080fd5b60008060408385031215610e7b57600080fd5b505080516020909101519092909150565b634e487b7160e01b600052601160045260246000fd5b81810381811115610eb557610eb5610e8c565b92915050565b600060208284031215610ecd57600080fd5b5051919050565b80820180821115610eb557610eb5610e8c565b60008060408385031215610efa57600080fd5b8251610f0581610c6c565b6020840151909250610f1681610c6c565b80915050925092905056fea2646970667358221220aeaa883c84de0fccf662af3a7e20e6eedbac84c3b551709ee9eceeb3724f55ff64736f6c634300081800330000000000000000000000008e4318e2cb1ae291254b187001a59a1f8ac78cef000000000000000000000000b58e61c3098d85632df34eecfb899a1ed80921cb000000000000000000000000b58e61c3098d85632df34eecfb899a1ed80921cb000000000000000000000000000000000000000000000000000000006bad937f0000000000000000000000000000000000000000000211654585005212800000","name":"UniswapAmplifier","is_blueprint":false,"license_type":"none","is_fully_verified":true,"is_verified_via_eth_bytecode_db":false,"language":"solidity","evm_version":"paris","can_be_visualized_via_sol2uml":true,"is_verified_via_sourcify":false,"additional_sources":[{"file_path":"@openzeppelin/contracts/proxy/Clones.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (proxy/Clones.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for\n * deploying minimal proxy contracts, also known as \"clones\".\n *\n * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies\n * > a minimal bytecode implementation that delegates all calls to a known, fixed address.\n *\n * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`\n * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the\n * deterministic method.\n *\n * _Available since v3.4._\n */\nlibrary Clones {\n    /**\n     * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.\n     *\n     * This function uses the create opcode, which should never revert.\n     */\n    function clone(address implementation) internal returns (address instance) {\n        assembly {\n            let ptr := mload(0x40)\n            mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)\n            mstore(add(ptr, 0x14), shl(0x60, implementation))\n            mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)\n            instance := create(0, ptr, 0x37)\n        }\n        require(instance != address(0), \"ERC1167: create failed\");\n    }\n\n    /**\n     * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.\n     *\n     * This function uses the create2 opcode and a `salt` to deterministically deploy\n     * the clone. Using the same `implementation` and `salt` multiple time will revert, since\n     * the clones cannot be deployed twice at the same address.\n     */\n    function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {\n        assembly {\n            let ptr := mload(0x40)\n            mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)\n            mstore(add(ptr, 0x14), shl(0x60, implementation))\n            mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)\n            instance := create2(0, ptr, 0x37, salt)\n        }\n        require(instance != address(0), \"ERC1167: create2 failed\");\n    }\n\n    /**\n     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.\n     */\n    function predictDeterministicAddress(\n        address implementation,\n        bytes32 salt,\n        address deployer\n    ) internal pure returns (address predicted) {\n        assembly {\n            let ptr := mload(0x40)\n            mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)\n            mstore(add(ptr, 0x14), shl(0x60, implementation))\n            mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf3ff00000000000000000000000000000000)\n            mstore(add(ptr, 0x38), shl(0x60, deployer))\n            mstore(add(ptr, 0x4c), salt)\n            mstore(add(ptr, 0x6c), keccak256(ptr, 0x37))\n            predicted := keccak256(add(ptr, 0x37), 0x55)\n        }\n    }\n\n    /**\n     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.\n     */\n    function predictDeterministicAddress(address implementation, bytes32 salt)\n        internal\n        view\n        returns (address predicted)\n    {\n        return predictDeterministicAddress(implementation, salt, address(this));\n    }\n}\n"},{"file_path":"contracts/equity/IGovernance.sol","source_code":"// SPDX-License-Identifier: MIT\r\npragma solidity ^0.8.0;\r\n\r\ninterface IGovernance {\r\n   function checkQualified(address sender, address[] calldata helpers) external view;\r\n   function delegateVoteTo(address delegate) external;\r\n}\r\n\r\nstruct SyncVote {\r\n    address voter;\r\n    uint256 votes;\r\n    address delegatee;\r\n}\r\n\r\nstruct SyncMessage {\r\n    SyncVote[] votes;\r\n    uint256 totalVotes;\r\n}\r\n"},{"file_path":"contracts/erc20/IERC20.sol","source_code":"/**\r\n * SPDX-License-Identifier: MIT\r\n *\r\n * Copyright (c) 2016-2019 zOS Global Limited\r\n *\r\n */\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @dev Interface of the ERC20 standard as defined in the EIP. Does not include\r\n * the optional functions; to access them see `ERC20Detailed`.\r\n */\r\n\r\ninterface IERC20 {\r\n    function name() external view returns (string memory);\r\n\r\n    function symbol() external view returns (string memory);\r\n\r\n    function decimals() external view returns (uint8);\r\n\r\n    /**\r\n     * @dev Returns the amount of tokens in existence.\r\n     */\r\n    function totalSupply() external view returns (uint256);\r\n\r\n    /**\r\n     * @dev Returns the amount of tokens owned by `account`.\r\n     */\r\n    function balanceOf(address account) external view returns (uint256);\r\n\r\n    /**\r\n     * @dev Moves `amount` tokens from the caller's account to `recipient`.\r\n     *\r\n     * Returns always true. Throws error on failure.\r\n     *\r\n     * Emits a `Transfer` event.\r\n     */\r\n    function transfer(address recipient, uint256 amount) external returns (bool);\r\n\r\n    /**\r\n     * @dev Returns the remaining number of tokens that `spender` will be\r\n     * allowed to spend on behalf of `owner` through `transferFrom`. This is\r\n     * zero by default.\r\n     *\r\n     * This value can change when `approve` or `transferFrom` are called.\r\n     */\r\n    function allowance(address owner, address spender) external view returns (uint256);\r\n\r\n    /**\r\n     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\r\n     *\r\n     * Returns a boolean value indicating whether the operation succeeded.\r\n     *\r\n     * > Beware that changing an allowance with this method brings the risk\r\n     * that someone may use both the old and the new allowance by unfortunate\r\n     * transaction ordering. One possible solution to mitigate this race\r\n     * condition is to first reduce the spender's allowance to 0 and set the\r\n     * desired value afterwards:\r\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\r\n     *\r\n     * Emits an `Approval` event.\r\n     */\r\n    function approve(address spender, uint256 amount) external returns (bool);\r\n\r\n    /**\r\n     * @dev Moves `amount` tokens from `sender` to `recipient` using the\r\n     * allowance mechanism. `amount` is then deducted from the caller's\r\n     * allowance.\r\n     *\r\n     * Returns always true. Throws error on failure.\r\n     *\r\n     * Emits a `Transfer` event.\r\n     */\r\n    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);\r\n\r\n    /**\r\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\r\n     * another (`to`).\r\n     *\r\n     * Note that `value` may be zero.\r\n     */\r\n    event Transfer(address indexed from, address indexed to, uint256 value);\r\n\r\n    /**\r\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\r\n     * a call to `approve`. `value` is the new allowance.\r\n     */\r\n    event Approval(address indexed owner, address indexed spender, uint256 value);\r\n}\r\n"},{"file_path":"contracts/erc20/SafeERC20.sol","source_code":"// SPDX-License-Identifier: MIT\r\n// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol)\r\n\r\npragma solidity ^0.8.20;\r\n\r\nimport {IERC20} from \"./IERC20.sol\";\r\n\r\n/**\r\n * @title SafeERC20\r\n * @dev Wrappers around ERC-20 operations that throw on failure (when the token\r\n * contract returns false). Tokens that return no value (and instead revert or\r\n * throw on failure) are also supported, non-reverting calls are assumed to be\r\n * successful.\r\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\r\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\r\n */\r\nlibrary SafeERC20 {\r\n    /**\r\n     * @dev An operation with an ERC-20 token failed.\r\n     */\r\n    error SafeERC20FailedOperation(address token);\r\n\r\n    /**\r\n     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\r\n     * non-reverting calls are assumed to be successful.\r\n     */\r\n    function safeTransfer(IERC20 token, address to, uint256 value) internal {\r\n        if (!_safeTransfer(token, to, value, true)) {\r\n            revert SafeERC20FailedOperation(address(token));\r\n        }\r\n    }\r\n\r\n    /**\r\n     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\r\n     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\r\n     */\r\n    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\r\n        if (!_safeTransferFrom(token, from, to, value, true)) {\r\n            revert SafeERC20FailedOperation(address(token));\r\n        }\r\n    }\r\n\r\n    /**\r\n     * @dev Imitates a Solidity `token.transfer(to, value)` call, relaxing the requirement on the return value: the\r\n     * return value is optional (but if data is returned, it must not be false).\r\n     *\r\n     * @param token The token targeted by the call.\r\n     * @param to The recipient of the tokens\r\n     * @param value The amount of token to transfer\r\n     * @param bubble Behavior switch if the transfer call reverts: bubble the revert reason or return a false boolean.\r\n     */\r\n    function _safeTransfer(IERC20 token, address to, uint256 value, bool bubble) private returns (bool success) {\r\n        bytes4 selector = IERC20.transfer.selector;\r\n\r\n        assembly (\"memory-safe\") {\r\n            let fmp := mload(0x40)\r\n            mstore(0x00, selector)\r\n            mstore(0x04, and(to, shr(96, not(0))))\r\n            mstore(0x24, value)\r\n            success := call(gas(), token, 0, 0, 0x44, 0, 0x20)\r\n            // if call success and return is true, all is good.\r\n            // otherwise (not success or return is not true), we need to perform further checks\r\n            if iszero(and(success, eq(mload(0x00), 1))) {\r\n                // if the call was a failure and bubble is enabled, bubble the error\r\n                if and(iszero(success), bubble) {\r\n                    returndatacopy(fmp, 0, returndatasize())\r\n                    revert(fmp, returndatasize())\r\n                }\r\n                // if the return value is not true, then the call is only successful if:\r\n                // - the token address has code\r\n                // - the returndata is empty\r\n                success := and(success, and(iszero(returndatasize()), gt(extcodesize(token), 0)))\r\n            }\r\n            mstore(0x40, fmp)\r\n        }\r\n    }\r\n\r\n    /**\r\n     * @dev Imitates a Solidity `token.transferFrom(from, to, value)` call, relaxing the requirement on the return\r\n     * value: the return value is optional (but if data is returned, it must not be false).\r\n     *\r\n     * @param token The token targeted by the call.\r\n     * @param from The sender of the tokens\r\n     * @param to The recipient of the tokens\r\n     * @param value The amount of token to transfer\r\n     * @param bubble Behavior switch if the transfer call reverts: bubble the revert reason or return a false boolean.\r\n     */\r\n    function _safeTransferFrom(IERC20 token, address from, address to, uint256 value, bool bubble) private returns (bool success) {\r\n        bytes4 selector = IERC20.transferFrom.selector;\r\n\r\n        assembly (\"memory-safe\") {\r\n            let fmp := mload(0x40)\r\n            mstore(0x00, selector)\r\n            mstore(0x04, and(from, shr(96, not(0))))\r\n            mstore(0x24, and(to, shr(96, not(0))))\r\n            mstore(0x44, value)\r\n            success := call(gas(), token, 0, 0, 0x64, 0, 0x20)\r\n            // if call success and return is true, all is good.\r\n            // otherwise (not success or return is not true), we need to perform further checks\r\n            if iszero(and(success, eq(mload(0x00), 1))) {\r\n                // if the call was a failure and bubble is enabled, bubble the error\r\n                if and(iszero(success), bubble) {\r\n                    returndatacopy(fmp, 0, returndatasize())\r\n                    revert(fmp, returndatasize())\r\n                }\r\n                // if the return value is not true, then the call is only successful if:\r\n                // - the token address has code\r\n                // - the returndata is empty\r\n                success := and(success, and(iszero(returndatasize()), gt(extcodesize(token), 0)))\r\n            }\r\n            mstore(0x40, fmp)\r\n            mstore(0x60, 0)\r\n        }\r\n    }\r\n}\r\n"},{"file_path":"contracts/stablecoin/IBasicFrankencoin.sol","source_code":"// SPDX-License-Identifier: MIT\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../erc20/IERC20.sol\";\r\nimport \"../equity/IGovernance.sol\";\r\n\r\ninterface IBasicFrankencoin is IERC20 {\r\n    function MIN_FEE() external view returns (uint256);\r\n\r\n    function MIN_APPLICATION_PERIOD() external view returns (uint256);\r\n\r\n    function suggestMinter(\r\n        address _minter,\r\n        uint256 _applicationPeriod,\r\n        uint256 _applicationFee,\r\n        string calldata _message\r\n    ) external;\r\n\r\n    function registerPosition(address position) external;\r\n\r\n    function denyMinter(address minter, address[] calldata helpers, string calldata message) external;\r\n\r\n    function reserve() external view returns (IGovernance);\r\n\r\n    function minters(address minter) external view returns (uint256);\r\n\r\n    function isMinter(address minter) external view returns (bool);\r\n\r\n    function getPositionParent(address position) external view returns (address);\r\n\r\n    function mint(address target, uint256 amount) external;\r\n\r\n    function burnFrom(address target, uint256 amount) external;\r\n\r\n    function burn(uint256 amount) external;\r\n\r\n    function coverLoss(address source, uint256 amount) external;\r\n\r\n    function collectProfits(address source, uint256 _amount) external;\r\n}\r\n"},{"file_path":"contracts/stablecoin/IFrankencoin.sol","source_code":"// SPDX-License-Identifier: MIT\r\npragma solidity ^0.8.0;\r\n\r\nimport \"../equity/IGovernance.sol\";\r\nimport \"./IBasicFrankencoin.sol\";\r\n\r\ninterface IFrankencoin is IBasicFrankencoin {\r\n\r\n    function minterReserve() external view returns (uint256);\r\n\r\n    function calculateAssignedReserve(uint256 mintedAmount, uint32 _reservePPM) external view returns (uint256);\r\n\r\n    function calculateFreedAmount(uint256 amountExcludingReserve, uint32 reservePPM) external view returns (uint256);\r\n\r\n    function equity() external view returns (uint256);\r\n\r\n    function mintWithReserve(address target, uint256 amount, uint32 reservePPM, uint32 feePPM) external;\r\n\r\n    function burnWithoutReserve(uint256 amountIncludingReserve, uint32 reservePPM) external;\r\n\r\n    function burnFromWithReserve(address payer, uint256 targetTotalBurnAmount, uint32 _reservePPM) external returns (uint256);\r\n\r\n    function burnWithReserve(uint256 amountExcludingReserve, uint32 reservePPM) external returns (uint256);\r\n\r\n}\r\n"},{"file_path":"contracts/swap/utils/IUniswapV3MintCallback.sol","source_code":"// SPDX-License-Identifier: GPL-2.0-or-later\r\npragma solidity >=0.5.0;\r\n\r\n/// @title Callback for IUniswapV3PoolActions#mint\r\n/// @notice Any contract that calls IUniswapV3PoolActions#mint must implement this interface\r\ninterface IUniswapV3MintCallback {\r\n    /// @notice Called to `msg.sender` after minting liquidity to a position from IUniswapV3Pool#mint.\r\n    /// @dev In the implementation you must pay the pool tokens owed for the minted liquidity.\r\n    /// The caller of this method must be checked to be a UniswapV3Pool deployed by the canonical UniswapV3Factory.\r\n    /// @param amount0Owed The amount of token0 due to the pool for the minted liquidity\r\n    /// @param amount1Owed The amount of token1 due to the pool for the minted liquidity\r\n    /// @param data Any data passed through by the caller via the IUniswapV3PoolActions#mint call\r\n    function uniswapV3MintCallback(\r\n        uint256 amount0Owed,\r\n        uint256 amount1Owed,\r\n        bytes calldata data\r\n    ) external;\r\n}"},{"file_path":"contracts/swap/utils/IUniswapV3Pool.sol","source_code":"// SPDX-License-Identifier: GPL-2.0-or-later\r\npragma solidity >=0.5.0;\r\n\r\n\r\n/// @title The interface for a Uniswap V3 Pool\r\n/// @notice A Uniswap pool facilitates swapping and automated market making between any two assets that strictly conform\r\n/// to the ERC20 specification\r\n/// @dev The pool interface is broken up into many smaller pieces\r\ninterface IUniswapV3Pool {\r\n\r\n    /// @notice Sets the initial price for the pool\r\n    /// @dev Price is represented as a sqrt(amountToken1/amountToken0) Q64.96 value\r\n    /// @param sqrtPriceX96 the initial sqrt price of the pool as a Q64.96\r\n    function initialize(uint160 sqrtPriceX96) external;\r\n\r\n    /// @notice Adds liquidity for the given recipient/tickLower/tickUpper position\r\n    /// @dev The caller of this method receives a callback in the form of IUniswapV3MintCallback#uniswapV3MintCallback\r\n    /// in which they must pay any token0 or token1 owed for the liquidity. The amount of token0/token1 due depends\r\n    /// on tickLower, tickUpper, the amount of liquidity, and the current price.\r\n    /// @param recipient The address for which the liquidity will be created\r\n    /// @param tickLower The lower tick of the position in which to add liquidity\r\n    /// @param tickUpper The upper tick of the position in which to add liquidity\r\n    /// @param amount The amount of liquidity to mint\r\n    /// @param data Any data that should be passed through to the callback\r\n    /// @return amount0 The amount of token0 that was paid to mint the given amount of liquidity. Matches the value in the callback\r\n    /// @return amount1 The amount of token1 that was paid to mint the given amount of liquidity. Matches the value in the callback\r\n    function mint(\r\n        address recipient,\r\n        int24 tickLower,\r\n        int24 tickUpper,\r\n        uint128 amount,\r\n        bytes calldata data\r\n    ) external returns (uint256 amount0, uint256 amount1);\r\n\r\n    /// @notice Collects tokens owed to a position\r\n    /// @dev Does not recompute fees earned, which must be done either via mint or burn of any amount of liquidity.\r\n    /// Collect must be called by the position owner. To withdraw only token0 or only token1, amount0Requested or\r\n    /// amount1Requested may be set to zero. To withdraw all tokens owed, caller may pass any value greater than the\r\n    /// actual tokens owed, e.g. type(uint128).max. Tokens owed may be from accumulated swap fees or burned liquidity.\r\n    /// @param recipient The address which should receive the fees collected\r\n    /// @param tickLower The lower tick of the position for which to collect fees\r\n    /// @param tickUpper The upper tick of the position for which to collect fees\r\n    /// @param amount0Requested How much token0 should be withdrawn from the fees owed\r\n    /// @param amount1Requested How much token1 should be withdrawn from the fees owed\r\n    /// @return amount0 The amount of fees collected in token0\r\n    /// @return amount1 The amount of fees collected in token1\r\n    function collect(\r\n        address recipient,\r\n        int24 tickLower,\r\n        int24 tickUpper,\r\n        uint128 amount0Requested,\r\n        uint128 amount1Requested\r\n    ) external returns (uint128 amount0, uint128 amount1);\r\n\r\n    /// @notice Burn liquidity from the sender and account tokens owed for the liquidity to the position\r\n    /// @dev Can be used to trigger a recalculation of fees owed to a position by calling with an amount of 0\r\n    /// @dev Fees must be collected separately via a call to #collect\r\n    /// @param tickLower The lower tick of the position for which to burn liquidity\r\n    /// @param tickUpper The upper tick of the position for which to burn liquidity\r\n    /// @param amount How much liquidity to burn\r\n    /// @return amount0 The amount of token0 sent to the recipient\r\n    /// @return amount1 The amount of token1 sent to the recipient\r\n    function burn(\r\n        int24 tickLower,\r\n        int24 tickUpper,\r\n        uint128 amount\r\n    ) external returns (uint256 amount0, uint256 amount1);\r\n\r\n    /// @notice Returns the information about a position by the position's key\r\n    /// @param key The position's key is a hash of a preimage composed by the owner, tickLower and tickUpper\r\n    /// @return liquidity The amount of liquidity in the position,\r\n    /// @return feeGrowthInside0LastX128 fee growth of token0 inside the tick range as of the last mint/burn/poke,\r\n    /// @return feeGrowthInside1LastX128 fee growth of token1 inside the tick range as of the last mint/burn/poke,\r\n    /// @return tokensOwed0 the computed amount of token0 owed to the position as of the last mint/burn/poke,\r\n    /// @return tokensOwed1 the computed amount of token1 owed to the position as of the last mint/burn/poke\r\n    function positions(bytes32 key)\r\n        external\r\n        view\r\n        returns (\r\n            uint128 liquidity,\r\n            uint256 feeGrowthInside0LastX128,\r\n            uint256 feeGrowthInside1LastX128,\r\n            uint128 tokensOwed0,\r\n            uint128 tokensOwed1\r\n        );\r\n\r\n    /// @notice The first of the two tokens of the pool, sorted by address\r\n    /// @return The token contract address\r\n    function token0() external view returns (address);\r\n\r\n    /// @notice The second of the two tokens of the pool, sorted by address\r\n    /// @return The token contract address\r\n    function token1() external view returns (address);\r\n\r\n    /// @notice The pool's fee in hundredths of a bip, i.e. 1e-6\r\n    /// @return The fee\r\n    function fee() external view returns (uint24);\r\n\r\n    /// @notice The pool tick spacing\r\n    /// @dev Ticks can only be used at multiples of this value, minimum of 1 and always positive\r\n    /// e.g.: a tickSpacing of 3 means ticks can be initialized every 3rd tick, i.e., ..., -6, -3, 0, 3, 6, ...\r\n    /// This value is an int24 to avoid casting even though it is always positive.\r\n    /// @return The tick spacing\r\n    function tickSpacing() external view returns (int24);\r\n\r\n    /// @notice The maximum amount of position liquidity that can use any tick in the range\r\n    /// @dev This parameter is enforced per tick to prevent liquidity from overflowing a uint128 at any point, and\r\n    /// also prevents out-of-range liquidity from being used to prevent adding in-range liquidity to a pool\r\n    /// @return The max amount of liquidity per tick\r\n    function maxLiquidityPerTick() external view returns (uint128);\r\n\r\n        /// @notice The 0th storage slot in the pool stores many values, and is exposed as a single method to save gas\r\n    /// when accessed externally.\r\n    /// @return sqrtPriceX96 The current price of the pool as a sqrt(token1/token0) Q64.96 value\r\n    /// tick The current tick of the pool, i.e. according to the last tick transition that was run.\r\n    /// This value may not always be equal to SqrtTickMath.getTickAtSqrtRatio(sqrtPriceX96) if the price is on a tick\r\n    /// boundary.\r\n    /// observationIndex The index of the last oracle observation that was written,\r\n    /// observationCardinality The current maximum number of observations stored in the pool,\r\n    /// observationCardinalityNext The next maximum number of observations, to be updated when the observation.\r\n    /// feeProtocol The protocol fee for both tokens of the pool.\r\n    /// Encoded as two 4 bit values, where the protocol fee of token1 is shifted 4 bits and the protocol fee of token0\r\n    /// is the lower 4 bits. Used as the denominator of a fraction of the swap fee, e.g. 4 means 1/4th of the swap fee.\r\n    /// unlocked Whether the pool is currently locked to reentrancy\r\n    function slot0()\r\n        external\r\n        view\r\n        returns (\r\n            uint160 sqrtPriceX96,\r\n            int24 tick,\r\n            uint16 observationIndex,\r\n            uint16 observationCardinality,\r\n            uint16 observationCardinalityNext,\r\n            uint8 feeProtocol,\r\n            bool unlocked\r\n        );\r\n\r\n\r\n}"},{"file_path":"contracts/utils/Math.sol","source_code":"// SPDX-License-Identifier: MIT\r\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)\r\n\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @dev Standard math utilities missing in the Solidity language.\r\n */\r\nlibrary Math {\r\n    enum Rounding {\r\n        Down, // Toward negative infinity\r\n        Up, // Toward infinity\r\n        Zero // Toward zero\r\n    }\r\n\r\n    /**\r\n     * @dev Returns the largest of two numbers.\r\n     */\r\n    function max(uint256 a, uint256 b) internal pure returns (uint256) {\r\n        return a > b ? a : b;\r\n    }\r\n\r\n    /**\r\n     * @dev Returns the smallest of two numbers.\r\n     */\r\n    function min(uint256 a, uint256 b) internal pure returns (uint256) {\r\n        return a < b ? a : b;\r\n    }\r\n\r\n    /**\r\n     * @dev Returns the average of two numbers. The result is rounded towards\r\n     * zero.\r\n     */\r\n    function average(uint256 a, uint256 b) internal pure returns (uint256) {\r\n        // (a + b) / 2 can overflow.\r\n        return (a & b) + (a ^ b) / 2;\r\n    }\r\n\r\n    /**\r\n     * @dev Returns the ceiling of the division of two numbers.\r\n     *\r\n     * This differs from standard division with `/` in that it rounds up instead\r\n     * of rounding down.\r\n     */\r\n    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\r\n        // (a + b - 1) / b can overflow on addition, so we distribute.\r\n        return a == 0 ? 0 : (a - 1) / b + 1;\r\n    }\r\n\r\n    /**\r\n     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\r\n     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\r\n     * with further edits by Uniswap Labs also under MIT license.\r\n     */\r\n    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {\r\n        unchecked {\r\n            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\r\n            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\r\n            // variables such that product = prod1 * 2^256 + prod0.\r\n            uint256 prod0; // Least significant 256 bits of the product\r\n            uint256 prod1; // Most significant 256 bits of the product\r\n            assembly {\r\n                let mm := mulmod(x, y, not(0))\r\n                prod0 := mul(x, y)\r\n                prod1 := sub(sub(mm, prod0), lt(mm, prod0))\r\n            }\r\n\r\n            // Handle non-overflow cases, 256 by 256 division.\r\n            if (prod1 == 0) {\r\n                // Solidity will revert if denominator == 0, unlike the div opcode on its own.\r\n                // The surrounding unchecked block does not change this fact.\r\n                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.\r\n                return prod0 / denominator;\r\n            }\r\n\r\n            // Make sure the result is less than 2^256. Also prevents denominator == 0.\r\n            require(denominator > prod1, \"Math: mulDiv overflow\");\r\n\r\n            ///////////////////////////////////////////////\r\n            // 512 by 256 division.\r\n            ///////////////////////////////////////////////\r\n\r\n            // Make division exact by subtracting the remainder from [prod1 prod0].\r\n            uint256 remainder;\r\n            assembly {\r\n                // Compute remainder using mulmod.\r\n                remainder := mulmod(x, y, denominator)\r\n\r\n                // Subtract 256 bit number from 512 bit number.\r\n                prod1 := sub(prod1, gt(remainder, prod0))\r\n                prod0 := sub(prod0, remainder)\r\n            }\r\n\r\n            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\r\n            // See https://cs.stackexchange.com/q/138556/92363.\r\n\r\n            // Does not overflow because the denominator cannot be zero at this stage in the function.\r\n            uint256 twos = denominator & (~denominator + 1);\r\n            assembly {\r\n                // Divide denominator by twos.\r\n                denominator := div(denominator, twos)\r\n\r\n                // Divide [prod1 prod0] by twos.\r\n                prod0 := div(prod0, twos)\r\n\r\n                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\r\n                twos := add(div(sub(0, twos), twos), 1)\r\n            }\r\n\r\n            // Shift in bits from prod1 into prod0.\r\n            prod0 |= prod1 * twos;\r\n\r\n            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\r\n            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\r\n            // four bits. That is, denominator * inv = 1 mod 2^4.\r\n            uint256 inverse = (3 * denominator) ^ 2;\r\n\r\n            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\r\n            // in modular arithmetic, doubling the correct bits in each step.\r\n            inverse *= 2 - denominator * inverse; // inverse mod 2^8\r\n            inverse *= 2 - denominator * inverse; // inverse mod 2^16\r\n            inverse *= 2 - denominator * inverse; // inverse mod 2^32\r\n            inverse *= 2 - denominator * inverse; // inverse mod 2^64\r\n            inverse *= 2 - denominator * inverse; // inverse mod 2^128\r\n            inverse *= 2 - denominator * inverse; // inverse mod 2^256\r\n\r\n            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\r\n            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\r\n            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\r\n            // is no longer required.\r\n            result = prod0 * inverse;\r\n            return result;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\r\n     */\r\n    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {\r\n        uint256 result = mulDiv(x, y, denominator);\r\n        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\r\n            result += 1;\r\n        }\r\n        return result;\r\n    }\r\n\r\n    /**\r\n     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\r\n     *\r\n     * Inspired by Henry S. Warren, Jr.'s \"Hacker's Delight\" (Chapter 11).\r\n     */\r\n    function sqrt(uint256 a) internal pure returns (uint256) {\r\n        if (a == 0) {\r\n            return 0;\r\n        }\r\n\r\n        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\r\n        //\r\n        // We know that the \"msb\" (most significant bit) of our target number `a` is a power of 2 such that we have\r\n        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\r\n        //\r\n        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\r\n        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\r\n        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\r\n        //\r\n        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\r\n        uint256 result = 1 << (log2(a) >> 1);\r\n\r\n        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\r\n        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\r\n        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\r\n        // into the expected uint128 result.\r\n        unchecked {\r\n            result = (result + a / result) >> 1;\r\n            result = (result + a / result) >> 1;\r\n            result = (result + a / result) >> 1;\r\n            result = (result + a / result) >> 1;\r\n            result = (result + a / result) >> 1;\r\n            result = (result + a / result) >> 1;\r\n            result = (result + a / result) >> 1;\r\n            return min(result, a / result);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * @notice Calculates sqrt(a), following the selected rounding direction.\r\n     */\r\n    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\r\n        unchecked {\r\n            uint256 result = sqrt(a);\r\n            return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * @dev Return the log in base 2, rounded down, of a positive value.\r\n     * Returns 0 if given 0.\r\n     */\r\n    function log2(uint256 value) internal pure returns (uint256) {\r\n        uint256 result = 0;\r\n        unchecked {\r\n            if (value >> 128 > 0) {\r\n                value >>= 128;\r\n                result += 128;\r\n            }\r\n            if (value >> 64 > 0) {\r\n                value >>= 64;\r\n                result += 64;\r\n            }\r\n            if (value >> 32 > 0) {\r\n                value >>= 32;\r\n                result += 32;\r\n            }\r\n            if (value >> 16 > 0) {\r\n                value >>= 16;\r\n                result += 16;\r\n            }\r\n            if (value >> 8 > 0) {\r\n                value >>= 8;\r\n                result += 8;\r\n            }\r\n            if (value >> 4 > 0) {\r\n                value >>= 4;\r\n                result += 4;\r\n            }\r\n            if (value >> 2 > 0) {\r\n                value >>= 2;\r\n                result += 2;\r\n            }\r\n            if (value >> 1 > 0) {\r\n                result += 1;\r\n            }\r\n        }\r\n        return result;\r\n    }\r\n\r\n    /**\r\n     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\r\n     * Returns 0 if given 0.\r\n     */\r\n    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\r\n        unchecked {\r\n            uint256 result = log2(value);\r\n            return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * @dev Return the log in base 10, rounded down, of a positive value.\r\n     * Returns 0 if given 0.\r\n     */\r\n    function log10(uint256 value) internal pure returns (uint256) {\r\n        uint256 result = 0;\r\n        unchecked {\r\n            if (value >= 10 ** 64) {\r\n                value /= 10 ** 64;\r\n                result += 64;\r\n            }\r\n            if (value >= 10 ** 32) {\r\n                value /= 10 ** 32;\r\n                result += 32;\r\n            }\r\n            if (value >= 10 ** 16) {\r\n                value /= 10 ** 16;\r\n                result += 16;\r\n            }\r\n            if (value >= 10 ** 8) {\r\n                value /= 10 ** 8;\r\n                result += 8;\r\n            }\r\n            if (value >= 10 ** 4) {\r\n                value /= 10 ** 4;\r\n                result += 4;\r\n            }\r\n            if (value >= 10 ** 2) {\r\n                value /= 10 ** 2;\r\n                result += 2;\r\n            }\r\n            if (value >= 10 ** 1) {\r\n                result += 1;\r\n            }\r\n        }\r\n        return result;\r\n    }\r\n\r\n    /**\r\n     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\r\n     * Returns 0 if given 0.\r\n     */\r\n    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\r\n        unchecked {\r\n            uint256 result = log10(value);\r\n            return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * @dev Return the log in base 256, rounded down, of a positive value.\r\n     * Returns 0 if given 0.\r\n     *\r\n     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\r\n     */\r\n    function log256(uint256 value) internal pure returns (uint256) {\r\n        uint256 result = 0;\r\n        unchecked {\r\n            if (value >> 128 > 0) {\r\n                value >>= 128;\r\n                result += 16;\r\n            }\r\n            if (value >> 64 > 0) {\r\n                value >>= 64;\r\n                result += 8;\r\n            }\r\n            if (value >> 32 > 0) {\r\n                value >>= 32;\r\n                result += 4;\r\n            }\r\n            if (value >> 16 > 0) {\r\n                value >>= 16;\r\n                result += 2;\r\n            }\r\n            if (value >> 8 > 0) {\r\n                result += 1;\r\n            }\r\n        }\r\n        return result;\r\n    }\r\n\r\n    /**\r\n     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.\r\n     * Returns 0 if given 0.\r\n     */\r\n    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\r\n        unchecked {\r\n            uint256 result = log256(value);\r\n            return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);\r\n        }\r\n    }\r\n}"},{"file_path":"contracts/utils/Ownable.sol","source_code":"// SPDX-License-Identifier: MIT\r\n//\r\n// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol\r\n//\r\n// Modifications:\r\n// - Replaced Context._msgSender() with msg.sender\r\n// - Made leaner\r\n\r\npragma solidity ^0.8.0;\r\n\r\n/**\r\n * @dev Contract module which provides a basic access control mechanism, where\r\n * there is an account (an owner) that can be granted exclusive access to\r\n * specific functions.\r\n *\r\n * By default, the owner account will be the one that deploys the contract. This\r\n * can later be changed with {transferOwnership}.\r\n */\r\ncontract Ownable {\r\n\r\n    address public owner;\r\n\r\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\r\n\r\n    error NotOwner();\r\n\r\n    /**\r\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\r\n     * Can only be called by the current owner.\r\n     */\r\n    function transferOwnership(address newOwner) public onlyOwner {\r\n        _setOwner(newOwner);\r\n    }\r\n\r\n    /**\r\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\r\n     * Internal function without access restriction.\r\n     */\r\n    function _setOwner(address newOwner) internal {\r\n        require(newOwner != address(0x0));\r\n        address oldOwner = owner;\r\n        owner = newOwner;\r\n        emit OwnershipTransferred(oldOwner, newOwner);\r\n    }\r\n\r\n    function _requireOwner(address sender) internal view {\r\n        if (owner != sender) revert NotOwner();\r\n    }\r\n\r\n    modifier onlyOwner() {\r\n        _requireOwner(msg.sender);\r\n        _;\r\n    }\r\n}\r\n"}],"certified":false,"conflicting_implementations":null,"abi":[{"inputs":[{"internalType":"address","name":"uniswapPool_","type":"address"},{"internalType":"address","name":"zchf_","type":"address"},{"internalType":"address","name":"zchfMinter_","type":"address"},{"internalType":"uint40","name":"expiration","type":"uint40"},{"internalType":"uint256","name":"borrowingLimit","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessDenied","type":"error"},{"inputs":[],"name":"AmplifierExpired","type":"error"},{"inputs":[{"internalType":"uint256","name":"requiredMinimum","type":"uint256"},{"internalType":"uint256","name":"actuallyFoundInProvidedRange","type":"uint256"}],"name":"InsufficientDollarsInRange","type":"error"},{"inputs":[{"internalType":"int24","name":"min","type":"int24"},{"internalType":"int24","name":"found","type":"int24"},{"internalType":"int24","name":"max","type":"int24"}],"name":"InvalidTick","type":"error"},{"inputs":[],"name":"InvalidUniswapPool","type":"error"},{"inputs":[{"internalType":"uint256","name":"newValue","type":"uint256"},{"internalType":"uint256","name":"limit","type":"uint256"}],"name":"LimitExceeded","type":"error"},{"inputs":[{"internalType":"uint256","name":"found","type":"uint256"},{"internalType":"uint256","name":"expected","type":"uint256"}],"name":"PriceChangedTooMuch","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"position","type":"address"}],"name":"AmplifiedPositionCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"borrowed","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalBorrowed","type":"uint256"}],"name":"Borrowed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalBorrowed","type":"uint256"}],"name":"Repaid","type":"event"},{"inputs":[],"name":"EXPIRATION","outputs":[{"internalType":"uint40","name":"","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LIMIT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAXIMUM_TICK","outputs":[{"internalType":"int24","name":"","type":"int24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_DOLLAR_APPRECIATION_TICKS","outputs":[{"internalType":"int24","name":"","type":"int24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_DOLLAR_DEPRECIATION_TICKS","outputs":[{"internalType":"int24","name":"","type":"int24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINIMUM_TICK","outputs":[{"internalType":"int24","name":"","type":"int24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PRICE_ANCHOR_X96","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UNISWAP_POOL","outputs":[{"internalType":"contract IUniswapV3Pool","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"USD","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ZCHF","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ZCHF_IS_TOKEN0","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ZCHF_MINTER","outputs":[{"internalType":"contract IFrankencoinMinter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"token0Amount","type":"uint256"},{"internalType":"uint256","name":"token1Amount","type":"uint256"}],"name":"borrowIntoPool","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"expectedPriceX96","type":"uint256"}],"name":"checkPrice","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"int24","name":"ticksLow","type":"int24"},{"internalType":"int24","name":"ticksHigh","type":"int24"}],"name":"checkTicks","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"int24","name":"tickLow","type":"int24"},{"internalType":"int24","name":"tickHigh","type":"int24"}],"name":"createAmplifiedPosition","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"exploitableAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"zchfAmount","type":"uint256"}],"name":"getMinimumDollars","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"positionCreationDate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"positionImplementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"borrowed","type":"uint256"},{"internalType":"uint128","name":"returnedPart","type":"uint128"},{"internalType":"uint128","name":"total","type":"uint128"}],"name":"repay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"totalBorrowed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}],"is_changed_bytecode":false,"is_partially_verified":false,"constructor_args":"0x0000000000000000000000008e4318e2cb1ae291254b187001a59a1f8ac78cef000000000000000000000000b58e61c3098d85632df34eecfb899a1ed80921cb000000000000000000000000b58e61c3098d85632df34eecfb899a1ed80921cb000000000000000000000000000000000000000000000000000000006bad937f0000000000000000000000000000000000000000000211654585005212800000"}