creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() external view returns (string memory);\n\n    /**\n     * @dev Returns the symbol of the token.\n     */\n    function symbol() external view returns (string memory);\n\n    /**\n     * @dev Returns the decimals places of the token.\n     */\n    function decimals() external view returns (uint8);\n}\n"
      },
      "@openzeppelin/contracts/token/ERC20/IERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n\n    /**\n     * @dev Returns the amount of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the amount of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves `amount` tokens from the caller's account to `to`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address to, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Moves `amount` tokens from `from` to `to` using the\n     * allowance mechanism. `amount` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address from, address to, uint256 amount) external returns (bool);\n}\n"
      },
      "@openzeppelin/contracts/utils/math/Math.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n    enum Rounding {\n        Down, // Toward negative infinity\n        Up, // Toward infinity\n        Zero // Toward zero\n    }\n\n    /**\n     * @dev Returns the largest of two numbers.\n     */\n    function max(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a > b ? a : b;\n    }\n\n    /**\n     * @dev Returns the smallest of two numbers.\n     */\n    function min(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a < b ? a : b;\n    }\n\n    /**\n     * @dev Returns the average of two numbers. The result is rounded towards\n     * zero.\n     */\n    function average(uint256 a, uint256 b) internal pure returns (uint256) {\n        // (a + b) / 2 can overflow.\n        return (a & b) + (a ^ b) / 2;\n    }\n\n    /**\n     * @dev Returns the ceiling of the division of two numbers.\n     *\n     * This differs from standard division with `/` in that it rounds up instead\n     * of rounding down.\n     */\n    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n        // (a + b - 1) / b can overflow on addition, so we distribute.\n        return a == 0 ? 0 : (a - 1) / b + 1;\n    }\n\n    /**\n     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\n     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\n     * with further edits by Uniswap Labs also under MIT license.\n     */\n    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {\n        unchecked {\n            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\n            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n            // variables such that product = prod1 * 2^256 + prod0.\n            uint256 prod0; // Least significant 256 bits of the product\n            uint256 prod1; // Most significant 256 bits of the product\n            assembly {\n                let mm := mulmod(x, y, not(0))\n                prod0 := mul(x, y)\n                prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n            }\n\n            // Handle non-overflow cases, 256 by 256 division.\n            if (prod1 == 0) {\n                // Solidity will revert if denominator == 0, unlike the div opcode on its own.\n                // The surrounding unchecked block does not change this fact.\n                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.\n                return prod0 / denominator;\n            }\n\n            // Make sure the result is less than 2^256. Also prevents denominator == 0.\n            require(denominator > prod1, \"Math: mulDiv overflow\");\n\n            ///////////////////////////////////////////////\n            // 512 by 256 division.\n            ///////////////////////////////////////////////\n\n            // Make division exact by subtracting the remainder from [prod1 prod0].\n            uint256 remainder;\n            assembly {\n                // Compute remainder using mulmod.\n                remainder := mulmod(x, y, denominator)\n\n                // Subtract 256 bit number from 512 bit number.\n                prod1 := sub(prod1, gt(remainder, prod0))\n                prod0 := sub(prod0, remainder)\n            }\n\n            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\n            // See https://cs.stackexchange.com/q/138556/92363.\n\n            // Does not overflow because the denominator cannot be zero at this stage in the function.\n            uint256 twos = denominator & (~denominator + 1);\n            assembly {\n                // Divide denominator by twos.\n                denominator := div(denominator, twos)\n\n                // Divide [prod1 prod0] by twos.\n                prod0 := div(prod0, twos)\n\n                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\n                twos := add(div(sub(0, twos), twos), 1)\n            }\n\n            // Shift in bits from prod1 into prod0.\n            prod0 |= prod1 * twos;\n\n            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\n            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\n            // four bits. That is, denominator * inv = 1 mod 2^4.\n            uint256 inverse = (3 * denominator) ^ 2;\n\n            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\n            // in modular arithmetic, doubling the correct bits in each step.\n            inverse *= 2 - denominator * inverse; // inverse mod 2^8\n            inverse *= 2 - denominator * inverse; // inverse mod 2^16\n            inverse *= 2 - denominator * inverse; // inverse mod 2^32\n            inverse *= 2 - denominator * inverse; // inverse mod 2^64\n            inverse *= 2 - denominator * inverse; // inverse mod 2^128\n            inverse *= 2 - denominator * inverse; // inverse mod 2^256\n\n            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\n            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\n            // is no longer required.\n            result = prod0 * inverse;\n            return result;\n        }\n    }\n\n    /**\n     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\n     */\n    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {\n        uint256 result = mulDiv(x, y, denominator);\n        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\n            result += 1;\n        }\n        return result;\n    }\n\n    /**\n     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\n     *\n     * Inspired by Henry S. Warren, Jr.'s \"Hacker's Delight\" (Chapter 11).\n     */\n    function sqrt(uint256 a) internal pure returns (uint256) {\n        if (a == 0) {\n            return 0;\n        }\n\n        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\n        //\n        // We know that the \"msb\" (most significant bit) of our target number `a` is a power of 2 such that we have\n        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\n        //\n        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\n        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\n        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\n        //\n        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\n        uint256 result = 1 << (log2(a) >> 1);\n\n        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\n        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\n        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\n        // into the expected uint128 result.\n        unchecked {\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            return min(result, a / result);\n        }\n    }\n\n    /**\n     * @notice Calculates sqrt(a), following the selected rounding direction.\n     */\n    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = sqrt(a);\n            return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 2, rounded down, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log2(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >> 128 > 0) {\n                value >>= 128;\n                result += 128;\n            }\n            if (value >> 64 > 0) {\n                value >>= 64;\n                result += 64;\n            }\n            if (value >> 32 > 0) {\n                value >>= 32;\n                result += 32;\n            }\n            if (value >> 16 > 0) {\n                value >>= 16;\n                result += 16;\n            }\n            if (value >> 8 > 0) {\n                value >>= 8;\n                result += 8;\n            }\n            if (value >> 4 > 0) {\n                value >>= 4;\n                result += 4;\n            }\n            if (value >> 2 > 0) {\n                value >>= 2;\n                result += 2;\n            }\n            if (value >> 1 > 0) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log2(value);\n            return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 10, rounded down, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log10(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >= 10 ** 64) {\n                value /= 10 ** 64;\n                result += 64;\n            }\n            if (value >= 10 ** 32) {\n                value /= 10 ** 32;\n                result += 32;\n            }\n            if (value >= 10 ** 16) {\n                value /= 10 ** 16;\n                result += 16;\n            }\n            if (value >= 10 ** 8) {\n                value /= 10 ** 8;\n                result += 8;\n            }\n            if (value >= 10 ** 4) {\n                value /= 10 ** 4;\n                result += 4;\n            }\n            if (value >= 10 ** 2) {\n                value /= 10 ** 2;\n                result += 2;\n            }\n            if (value >= 10 ** 1) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log10(value);\n            return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 256, rounded down, of a positive value.\n     * Returns 0 if given 0.\n     *\n     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\n     */\n    function log256(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >> 128 > 0) {\n                value >>= 128;\n                result += 16;\n            }\n            if (value >> 64 > 0) {\n                value >>= 64;\n                result += 8;\n            }\n            if (value >> 32 > 0) {\n                value >>= 32;\n                result += 4;\n            }\n            if (value >> 16 > 0) {\n                value >>= 16;\n                result += 2;\n            }\n            if (value >> 8 > 0) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log256(value);\n            return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);\n        }\n    }\n}\n"
      },
      "contracts/Fees.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n// Base V1 Fees contract is used as a 1:1 pair relationship to split out fees, this ensures that the curve does not need to be modified for LP shares\ncontract Fees {\n\n    address internal immutable pair; // The pair it is bonded to\n    address internal immutable token0; // token0 of pair, saved localy and statically for gas optimization\n    address internal immutable token1; // Token1 of pair, saved localy and statically for gas optimization\n\n    constructor(address _token0, address _token1) {\n        pair = msg.sender;\n        token0 = _token0;\n        token1 = _token1;\n    }\n\n    function _safeTransfer(address token,address to,uint256 value) internal {\n        require(token.code.length > 0);\n        (bool success, bytes memory data) =\n        token.call(abi.encodeWithSelector(IERC20.transfer.selector, to, value));\n        require(success && (data.length == 0 || abi.decode(data, (bool))));\n    }\n\n    // Allow the pair to transfer fees to users\n    function claimFeesFor(address recipient, uint amount0, uint amount1) external {\n        require(msg.sender == pair);\n        if (amount0 > 0) _safeTransfer(token0, recipient, amount0);\n        if (amount1 > 0) _safeTransfer(token1, recipient, amount1);\n    }\n\n}"
      },
      "contracts/interfaces/ICallee.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\ninterface ICallee {\n    function hook(address sender, uint amount0, uint amount1, bytes calldata data) external;\n}"
      },
      "contracts/interfaces/IPair.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\ninterface IPair {\n    function burn(address to) external returns (uint amount0, uint amount1);\n    function claimFees() external returns (uint, uint);\n    function getAmountOut(uint amountIn, address tokenIn) external view returns (uint);\n    function getReserves() external view returns (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast);\n    function mint(address to) external returns (uint liquidity);\n    function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;\n    function stable() external view returns (bool);\n    function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;\n    function tokens() external returns (address, address);\n    function transferFrom(address src, address dst, uint amount) external returns (bool);\n}"
      },
      "contracts/interfaces/IPairFactory.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\ninterface IPairFactory {\n    function admin() external view returns (address);\n    function feeManagers(address feeManager) external view returns (bool);\n    function allPairsLength() external view returns (uint);\n    function isPair(address pair) external view returns (bool);\n    function pairCodeHash() external pure returns (bytes32);\n    function getPair(address tokenA, address token, bool stable) external view returns (address);\n    function createPair(address tokenA, address tokenB, bool stable) external returns (address pair);\n    function getInitializable() external view returns (address, address, bool);\n    function setPause(bool _state) external;\n    function isPaused() external view returns (bool);\n    function getFee(bool _stable) external view returns(uint256);\n    function getRealFee(address _pair) external view returns(uint256);\n}"
      },
      "contracts/Pair.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\nimport {Math} from \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {IERC20Metadata} from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport {ICallee} from \"./interfaces/ICallee.sol\";\nimport {IPairFactory} from \"./interfaces/IPairFactory.sol\";\nimport {Fees} from \"./Fees.sol\";\n\n// The base pair of pools, either stable or volatile\ncontract Pair {\n\n    string public name;\n    string public symbol;\n    uint8 public constant decimals = 18;\n\n    // Used to denote stable or volatile pair, not immutable since construction happens in the initialize method for CREATE2 deterministic addresses\n    bool public immutable stable;\n\n    uint public totalSupply = 0;\n\n    mapping(address => mapping (address => uint)) public allowance;\n    mapping(address => uint) public balanceOf;\n\n    bytes32 internal DOMAIN_SEPARATOR;\n    // keccak256(\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\");\n    bytes32 internal constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;\n    mapping(address => uint) public nonces;\n\n    uint internal constant MINIMUM_LIQUIDITY = 10**3;\n\n    address public immutable token0;\n    address public immutable token1;\n    address public immutable fees;\n    address immutable factory;\n\n    // Structure to capture time period obervations every 30 minutes, used for local oracles\n    struct Observation {\n        uint timestamp;\n        uint reserve0Cumulative;\n        uint reserve1Cumulative;\n    }\n\n    // Capture oracle reading every 30 minutes\n    uint constant periodSize = 1800;\n\n    Observation[] public observations;\n\n    uint internal immutable decimals0;\n    uint internal immutable decimals1;\n\n    uint public reserve0;\n    uint public reserve1;\n    uint public blockTimestampLast;\n\n    uint public reserve0CumulativeLast;\n    uint public reserve1CumulativeLast;\n\n    // index0 and index1 are used to accumulate fees, this is split out from normal trades to keep the swap \"clean\"\n    // this further allows LP holders to easily claim fees for tokens they have/staked\n    uint public index0 = 0;\n    uint public index1 = 0;\n\n    // position assigned to each LP to track their current index0 & index1 vs the global position\n    mapping(address => uint) public supplyIndex0;\n    mapping(address => uint) public supplyIndex1;\n\n    // tracks the amount of unclaimed, but claimable tokens off of fees for token0 and token1\n    mapping(address => uint) public claimable0;\n    mapping(address => uint) public claimable1;\n\n    event Fee(address indexed sender, uint amount0, uint amount1);\n    event Mint(address indexed sender, uint amount0, uint amount1);\n    event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);\n    event Swap(\n        address indexed sender,\n        uint amount0In,\n        uint amount1In,\n        uint amount0Out,\n        uint amount1Out,\n        address indexed to\n    );\n    event Sync(uint reserve0, uint reserve1);\n    event Claim(address indexed sender, address indexed recipient, uint amount0, uint amount1);\n\n    event Transfer(address indexed from, address indexed to, uint amount);\n    event Approval(address indexed owner, address indexed spender, uint amount);\n\n    constructor() {\n        factory = msg.sender;\n        (address _token0, address _token1, bool _stable) = IPairFactory(msg.sender).getInitializable();\n        (token0, token1, stable) = (_token0, _token1, _stable);\n        fees = address(new Fees(_token0, _token1));\n        if (_stable) {\n            name = string(abi.encodePacked(\"Archly DEX Stable AMM - \", IERC20Metadata(_token0).symbol(), \"/\", IERC20Metadata(_token1).symbol()));\n            symbol = string(abi.encodePacked(\"sAMM-\", IERC20Metadata(_token0).symbol(), \"/\", IERC20Metadata(_token1).symbol()));\n        } else {\n            name = string(abi.encodePacked(\"Archly DEX Volatile AMM - \", IERC20Metadata(_token0).symbol(), \"/\", IERC20Metadata(_token1).symbol()));\n            symbol = string(abi.encodePacked(\"vAMM-\", IERC20Metadata(_token0).symbol(), \"/\", IERC20Metadata(_token1).symbol()));\n        }\n\n        decimals0 = 10**IERC20Metadata(_token0).decimals();\n        decimals1 = 10**IERC20Metadata(_token1).decimals();\n\n        observations.push(Observation(block.timestamp, 0, 0));\n    }\n\n    // simple re-entrancy check\n    uint internal _unlocked = 1;\n    modifier lock() {\n        require(_unlocked == 1);\n        _unlocked = 2;\n        _;\n        _unlocked = 1;\n    }\n\n    function observationLength() external view returns (uint) {\n        return observations.length;\n    }\n\n    function lastObservation() public view returns (Observation memory) {\n        return observations[observations.length-1];\n    }\n\n    function metadata() external view returns (uint dec0, uint dec1, uint r0, uint r1, bool st, address t0, address t1) {\n        return (decimals0, decimals1, reserve0, reserve1, stable, token0, token1);\n    }\n\n    function tokens() external view returns (address, address) {\n        return (token0, token1);\n    }\n\n    // claim accumulated but unclaimed fees (viewable via claimable0 and claimable1)\n    function claimFees() external returns (uint claimed0, uint claimed1) {\n        _updateFor(msg.sender);\n\n        claimed0 = claimable0[msg.sender];\n        claimed1 = claimable1[msg.sender];\n\n        if (claimed0 > 0 || claimed1 > 0) {\n            claimable0[msg.sender] = 0;\n            claimable1[msg.sender] = 0;\n\n            Fees(fees).claimFeesFor(msg.sender, claimed0, claimed1);\n\n            emit Claim(msg.sender, msg.sender, claimed0, claimed1);\n        }\n    }\n\n    // Accrue fees on token0\n    function _update0(uint amount) internal {\n        _safeTransfer(token0, fees, amount); // transfer the fees out to Fees\n        uint256 _ratio = amount * 1e18 / totalSupply; // 1e18 adjustment is removed during claim\n        if (_ratio > 0) {\n            index0 += _ratio;\n        }\n        emit Fee(msg.sender, amount, 0);\n    }\n\n    // Accrue fees on token1\n    function _update1(uint amount) internal {\n        _safeTransfer(token1, fees, amount);\n        uint256 _ratio = amount * 1e18 / totalSupply;\n        if (_ratio > 0) {\n            index1 += _ratio;\n        }\n        emit Fee(msg.sender, 0, amount);\n    }\n\n    // this function MUST be called on any balance changes, otherwise can be used to infinitely claim fees\n    // Fees are segregated from core funds, so fees can never put liquidity at risk\n    function _updateFor(address recipient) internal {\n        uint _supplied = balanceOf[recipient]; // get LP balance of `recipient`\n        if (_supplied > 0) {\n            uint _supplyIndex0 = supplyIndex0[recipient]; // get last adjusted index0 for recipient\n            uint _supplyIndex1 = supplyIndex1[recipient];\n            uint _index0 = index0; // get global index0 for accumulated fees\n            uint _index1 = index1;\n            supplyIndex0[recipient] = _index0; // update user current position to global position\n            supplyIndex1[recipient] = _index1;\n            uint _delta0 = _index0 - _supplyIndex0; // see if there is any difference that need to be accrued\n            uint _delta1 = _index1 - _supplyIndex1;\n            if (_delta0 > 0) {\n                uint _share = _supplied * _delta0 / 1e18; // add accrued difference for each supplied token\n                claimable0[recipient] += _share;\n            }\n            if (_delta1 > 0) {\n                uint _share = _supplied * _delta1 / 1e18;\n                claimable1[recipient] += _share;\n            }\n        } else {\n            supplyIndex0[recipient] = index0; // new users are set to the default global state\n            supplyIndex1[recipient] = index1;\n        }\n    }\n\n    function getReserves() public view returns (uint _reserve0, uint _reserve1, uint _blockTimestampLast) {\n        _reserve0 = reserve0;\n        _reserve1 = reserve1;\n        _blockTimestampLast = blockTimestampLast;\n    }\n\n    // update reserves and, on the first call per block, price accumulators\n    function _update(uint balance0, uint balance1, uint _reserve0, uint _reserve1) internal {\n        uint blockTimestamp = block.timestamp;\n        uint timeElapsed = blockTimestamp - blockTimestampLast; // overflow is desired\n        if (timeElapsed > 0 && _reserve0 != 0 && _reserve1 != 0) {\n            reserve0CumulativeLast += _reserve0 * timeElapsed;\n            reserve1CumulativeLast += _reserve1 * timeElapsed;\n        }\n\n        Observation memory _point = lastObservation();\n        timeElapsed = blockTimestamp - _point.timestamp; // compare the last observation with current timestamp, if greater than 30 minutes, record a new event\n        if (timeElapsed > periodSize) {\n            observations.push(Observation(blockTimestamp, reserve0CumulativeLast, reserve1CumulativeLast));\n        }\n        reserve0 = balance0;\n        reserve1 = balance1;\n        blockTimestampLast = blockTimestamp;\n        emit Sync(reserve0, reserve1);\n    }\n\n    // produces the cumulative price using counterfactuals to save gas and avoid a call to sync.\n    function currentCumulativePrices() public view returns (uint reserve0Cumulative, uint reserve1Cumulative, uint blockTimestamp) {\n        blockTimestamp = block.timestamp;\n        reserve0Cumulative = reserve0CumulativeLast;\n        reserve1Cumulative = reserve1CumulativeLast;\n\n        // if time has elapsed since the last update on the pair, mock the accumulated price values\n        (uint _reserve0, uint _reserve1, uint _blockTimestampLast) = getReserves();\n        if (_blockTimestampLast != blockTimestamp) {\n            // subtraction overflow is desired\n            uint timeElapsed = blockTimestamp - _blockTimestampLast;\n            reserve0Cumulative += _reserve0 * timeElapsed;\n            reserve1Cumulative += _reserve1 * timeElapsed;\n        }\n    }\n\n    // gives the current twap price measured from amountIn * tokenIn gives amountOut\n    function current(address tokenIn, uint amountIn) external view returns (uint amountOut) {\n        Observation memory _observation = lastObservation();\n        (uint reserve0Cumulative, uint reserve1Cumulative,) = currentCumulativePrices();\n        if (block.timestamp == _observation.timestamp) {\n            _observation = observations[observations.length-2];\n        }\n\n        uint timeElapsed = block.timestamp - _observation.timestamp;\n        uint _reserve0 = (reserve0Cumulative - _observation.reserve0Cumulative) / timeElapsed;\n        uint _reserve1 = (reserve1Cumulative - _observation.reserve1Cumulative) / timeElapsed;\n        amountOut = _getAmountOut(amountIn, tokenIn, _reserve0, _reserve1);\n    }\n\n    // as per `current`, however allows user configured granularity, up to the full window size\n    function quote(address tokenIn, uint amountIn, uint granularity) external view returns (uint amountOut) {\n        uint [] memory _prices = sample(tokenIn, amountIn, granularity, 1);\n        uint priceAverageCumulative;\n        for (uint i = 0; i < _prices.length; i++) {\n            priceAverageCumulative += _prices[i];\n        }\n        return priceAverageCumulative / granularity;\n    }\n\n    // returns a memory set of twap prices\n    function prices(address tokenIn, uint amountIn, uint points) external view returns (uint[] memory) {\n        return sample(tokenIn, amountIn, points, 1);\n    }\n\n    function sample(address tokenIn, uint amountIn, uint points, uint window) public view returns (uint[] memory) {\n        uint[] memory _prices = new uint[](points);\n\n        uint length = observations.length-1;\n        uint i = length - (points * window);\n        uint nextIndex = 0;\n        uint index = 0;\n\n        for (; i < length; i+=window) {\n            nextIndex = i + window;\n            uint timeElapsed = observations[nextIndex].timestamp - observations[i].timestamp;\n            uint _reserve0 = (observations[nextIndex].reserve0Cumulative - observations[i].reserve0Cumulative) / timeElapsed;\n            uint _reserve1 = (observations[nextIndex].reserve1Cumulative - observations[i].reserve1Cumulative) / timeElapsed;\n            _prices[index] = _getAmountOut(amountIn, tokenIn, _reserve0, _reserve1);\n            // index < length; length cannot overflow\n            unchecked {\n                index = index + 1;\n            }\n        }\n        return _prices;\n    }\n\n    // this low-level function should be called from a contract which performs important safety checks\n    // standard uniswap v2 implementation\n    function mint(address to) external lock returns (uint liquidity) {\n        (uint _reserve0, uint _reserve1) = (reserve0, reserve1);\n        uint _balance0 = IERC20(token0).balanceOf(address(this));\n        uint _balance1 = IERC20(token1).balanceOf(address(this));\n        uint _amount0 = _balance0 - _reserve0;\n        uint _amount1 = _balance1 - _reserve1;\n\n        uint _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee\n        if (_totalSupply == 0) {\n            liquidity = Math.sqrt(_amount0 * _amount1) - MINIMUM_LIQUIDITY;\n            _mint(address(0), MINIMUM_LIQUIDITY); // permanently lock the first MINIMUM_LIQUIDITY tokens\n        } else {\n            liquidity = Math.min(_amount0 * _totalSupply / _reserve0, _amount1 * _totalSupply / _reserve1);\n        }\n        require(liquidity > 0, 'ILM'); // Pair: INSUFFICIENT_LIQUIDITY_MINTED\n        _mint(to, liquidity);\n\n        _update(_balance0, _balance1, _reserve0, _reserve1);\n        emit Mint(msg.sender, _amount0, _amount1);\n    }\n\n    // this low-level function should be called from a contract which performs important safety checks\n    // standard uniswap v2 implementation\n    function burn(address to) external lock returns (uint amount0, uint amount1) {\n        (uint _reserve0, uint _reserve1) = (reserve0, reserve1);\n        (address _token0, address _token1) = (token0, token1);\n        uint _balance0 = IERC20(_token0).balanceOf(address(this));\n        uint _balance1 = IERC20(_token1).balanceOf(address(this));\n        uint _liquidity = balanceOf[address(this)];\n\n        uint _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee\n        amount0 = _liquidity * _balance0 / _totalSupply; // using balances ensures pro-rata distribution\n        amount1 = _liquidity * _balance1 / _totalSupply; // using balances ensures pro-rata distribution\n        require(amount0 > 0 && amount1 > 0, 'ILB'); // Pair: INSUFFICIENT_LIQUIDITY_BURNED\n        _burn(address(this), _liquidity);\n        _safeTransfer(_token0, to, amount0);\n        _safeTransfer(_token1, to, amount1);\n        _balance0 = IERC20(_token0).balanceOf(address(this));\n        _balance1 = IERC20(_token1).balanceOf(address(this));\n\n        _update(_balance0, _balance1, _reserve0, _reserve1);\n        emit Burn(msg.sender, amount0, amount1, to);\n    }\n\n    // this low-level function should be called from a contract which performs important safety checks\n    function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external lock {\n        require(!IPairFactory(factory).isPaused());\n        require(amount0Out > 0 || amount1Out > 0, 'IOA'); // Pair: INSUFFICIENT_OUTPUT_AMOUNT\n        (uint _reserve0, uint _reserve1) =  (reserve0, reserve1);\n        require(amount0Out < _reserve0 && amount1Out < _reserve1, 'IL'); // Pair: INSUFFICIENT_LIQUIDITY\n\n        uint _balance0;\n        uint _balance1;\n        { // scope for _token{0,1}, avoids stack too deep errors\n        (address _token0, address _token1) = (token0, token1);\n        require(to != _token0 && to != _token1, 'IT'); // Pair: INVALID_TO\n        if (amount0Out > 0) _safeTransfer(_token0, to, amount0Out); // optimistically transfer tokens\n        if (amount1Out > 0) _safeTransfer(_token1, to, amount1Out); // optimistically transfer tokens\n        if (data.length > 0) ICallee(to).hook(msg.sender, amount0Out, amount1Out, data); // callback, used for flash loans\n        _balance0 = IERC20(_token0).balanceOf(address(this));\n        _balance1 = IERC20(_token1).balanceOf(address(this));\n        }\n        uint amount0In = _balance0 > _reserve0 - amount0Out ? _balance0 - (_reserve0 - amount0Out) : 0;\n        uint amount1In = _balance1 > _reserve1 - amount1Out ? _balance1 - (_reserve1 - amount1Out) : 0;\n        require(amount0In > 0 || amount1In > 0, 'IIA'); // Pair: INSUFFICIENT_INPUT_AMOUNT\n        { // scope for reserve{0,1}Adjusted, avoids stack too deep errors\n        (address _token0, address _token1) = (token0, token1);\n        if (amount0In > 0) _update0(amount0In * IPairFactory(factory).getFee(stable) / 10000); // accrue fees for token0 and move them out of pool\n        if (amount1In > 0) _update1(amount1In * IPairFactory(factory).getFee(stable) / 10000); // accrue fees for token1 and move them out of pool\n        _balance0 = IERC20(_token0).balanceOf(address(this)); // since we removed tokens, we need to reconfirm balances, can also simply use previous balance - amountIn/ 10000, but doing balanceOf again as safety check\n        _balance1 = IERC20(_token1).balanceOf(address(this));\n        // The curve, either x3y+y3x for stable pools, or x*y for volatile pools\n        require(_k(_balance0, _balance1) >= _k(_reserve0, _reserve1), 'K'); // Pair: K\n        }\n\n        _update(_balance0, _balance1, _reserve0, _reserve1);\n        emit Swap(msg.sender, amount0In, amount1In, amount0Out, amount1Out, to);\n    }\n\n    // force balances to match reserves\n    function skim(address to) external lock {\n        (address _token0, address _token1) = (token0, token1);\n        _safeTransfer(_token0, to, IERC20(_token0).balanceOf(address(this)) - (reserve0));\n        _safeTransfer(_token1, to, IERC20(_token1).balanceOf(address(this)) - (reserve1));\n    }\n\n    // force reserves to match balances\n    function sync() external lock {\n        _update(IERC20(token0).balanceOf(address(this)), IERC20(token1).balanceOf(address(this)), reserve0, reserve1);\n    }\n\n    function _f(uint x0, uint y) internal pure returns (uint) {\n        return x0*(y*y/1e18*y/1e18)/1e18+(x0*x0/1e18*x0/1e18)*y/1e18;\n    }\n\n    function _d(uint x0, uint y) internal pure returns (uint) {\n        return 3*x0*(y*y/1e18)/1e18+(x0*x0/1e18*x0/1e18);\n    }\n\n    function _get_y(uint x0, uint xy, uint y) internal pure returns (uint) {\n        for (uint i = 0; i < 255; i++) {\n            uint y_prev = y;\n            uint k = _f(x0, y);\n            if (k < xy) {\n                uint dy = (xy - k)*1e18/_d(x0, y);\n                y = y + dy;\n            } else {\n                uint dy = (k - xy)*1e18/_d(x0, y);\n                y = y - dy;\n            }\n            if (y > y_prev) {\n                if (y - y_prev <= 1) {\n                    return y;\n                }\n            } else {\n                if (y_prev - y <= 1) {\n                    return y;\n                }\n            }\n        }\n        return y;\n    }\n\n    function getAmountOut(uint amountIn, address tokenIn) external view returns (uint) {\n        (uint _reserve0, uint _reserve1) = (reserve0, reserve1);\n        amountIn -= amountIn * IPairFactory(factory).getFee(stable) / 10000; // remove fee from amount received\n        return _getAmountOut(amountIn, tokenIn, _reserve0, _reserve1);\n    }\n\n    function _getAmountOut(uint amountIn, address tokenIn, uint _reserve0, uint _reserve1) internal view returns (uint) {\n        if (stable) {\n            uint xy =  _k(_reserve0, _reserve1);\n            _reserve0 = _reserve0 * 1e18 / decimals0;\n            _reserve1 = _reserve1 * 1e18 / decimals1;\n            (uint reserveA, uint reserveB) = tokenIn == token0 ? (_reserve0, _reserve1) : (_reserve1, _reserve0);\n            amountIn = tokenIn == token0 ? amountIn * 1e18 / decimals0 : amountIn * 1e18 / decimals1;\n            uint y = reserveB - _get_y(amountIn+reserveA, xy, reserveB);\n            return y * (tokenIn == token0 ? decimals1 : decimals0) / 1e18;\n        } else {\n            (uint reserveA, uint reserveB) = tokenIn == token0 ? (_reserve0, _reserve1) : (_reserve1, _reserve0);\n            return amountIn * reserveB / (reserveA + amountIn);\n        }\n    }\n\n    function _k(uint x, uint y) internal view returns (uint) {\n        if (stable) {\n            uint _x = x * 1e18 / decimals0;\n            uint _y = y * 1e18 / decimals1;\n            uint _a = (_x * _y) / 1e18;\n            uint _b = ((_x * _x) / 1e18 + (_y * _y) / 1e18);\n            return _a * _b / 1e18;  // x3y+y3x >= k\n        } else {\n            return x * y; // xy >= k\n        }\n    }\n\n    function _mint(address dst, uint amount) internal {\n        _updateFor(dst); // balances must be updated on mint/burn/transfer\n        totalSupply += amount;\n        balanceOf[dst] += amount;\n        emit Transfer(address(0), dst, amount);\n    }\n\n    function _burn(address dst, uint amount) internal {\n        _updateFor(dst);\n        totalSupply -= amount;\n        balanceOf[dst] -= amount;\n        emit Transfer(dst, address(0), amount);\n    }\n\n    function approve(address spender, uint amount) external returns (bool) {\n        allowance[msg.sender][spender] = amount;\n\n        emit Approval(msg.sender, spender, amount);\n        return true;\n    }\n\n    function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external {\n        require(deadline >= block.timestamp, 'Pair: EXPIRED');\n        DOMAIN_SEPARATOR = keccak256(\n            abi.encode(\n                keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'),\n                keccak256(bytes(name)),\n                keccak256(bytes('1')),\n                block.chainid,\n                address(this)\n            )\n        );\n        bytes32 digest = keccak256(\n            abi.encodePacked(\n                '\\x19\\x01',\n                DOMAIN_SEPARATOR,\n                keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline))\n            )\n        );\n        address recoveredAddress = ecrecover(digest, v, r, s);\n        require(recoveredAddress != address(0) && recoveredAddress == owner, 'Pair: INVALID_SIGNATURE');\n        allowance[owner][spender] = value;\n\n        emit Approval(owner, spender, value);\n    }\n\n    function transfer(address dst, uint amount) external returns (bool) {\n        _transferTokens(msg.sender, dst, amount);\n        return true;\n    }\n\n    function transferFrom(address src, address dst, uint amount) external returns (bool) {\n        address spender = msg.sender;\n        uint spenderAllowance = allowance[src][spender];\n\n        if (spender != src && spenderAllowance != type(uint).max) {\n            uint newAllowance = spenderAllowance - amount;\n            allowance[src][spender] = newAllowance;\n\n            emit Approval(src, spender, newAllowance);\n        }\n\n        _transferTokens(src, dst, amount);\n        return true;\n    }\n\n    function _transferTokens(address src, address dst, uint amount) internal {\n        _updateFor(src); // update fee position for src\n        _updateFor(dst); // update fee position for dst\n\n        balanceOf[src] -= amount;\n        balanceOf[dst] += amount;\n\n        emit Transfer(src, dst, amount);\n    }\n\n    function _safeTransfer(address token,address to,uint256 value) internal {\n        require(token.code.length > 0);\n        (bool success, bytes memory data) =\n        token.call(abi.encodeWithSelector(IERC20.transfer.selector, to, value));\n        require(success && (data.length == 0 || abi.decode(data, (bool))));\n    }\n}"
      },
      "contracts/PairFactory.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\nimport {IPair} from \"./interfaces/IPair.sol\";\nimport {Pair} from \"./Pair.sol\";\n\ncontract PairFactory {\n\n    bool public isPaused;\n    address public admin;\n    address public pendingAdmin;\n    \n    uint256 public stableFee;\n    uint256 public volatileFee;\n    uint256 public constant MAX_FEE = 500; // 5%\n    mapping(address => bool) public feeManagers;\n\n    mapping(address => mapping(address => mapping(bool => address))) public getPair;\n    address[] public allPairs;\n    mapping(address => bool) public isPair; // simplified check if its a pair, given that `stable` flag might not be available in peripherals\n    mapping(address => uint256) public feesOverrides;\n    \n    address internal _temp0;\n    address internal _temp1;\n    bool internal _temp;\n\n    event PairCreated(address indexed token0, address indexed token1, bool stable, address pair, uint);\n\n    constructor() {\n        isPaused = false;\n        stableFee = 5; // 0.05%, Base: 10000\n        volatileFee = 30; // 0.30%, Base: 10000\n        admin = msg.sender;\n        feeManagers[msg.sender] = true;\n        feeManagers[0x0c5D52630c982aE81b78AB2954Ddc9EC2797bB9c] = true;\n        feeManagers[0x726461FA6e788bd8a79986D36F1992368A3e56eA] = true;\n    }\n    \n    modifier onlyAdmin() {\n        require(msg.sender == admin, \"PairFactory: only admin\");\n        _;\n    }\n    \n    modifier onlyFeeManagers() \n    {\n        require(feeManagers[msg.sender], 'PairFactory: only fee manager');\n        _;\n    }\n\n    function allPairsLength() external view returns (uint) {\n        return allPairs.length;\n    }\n    \n    function setAdmin(address _admin) external onlyAdmin {\n        pendingAdmin = _admin;\n    }\n\n    function acceptAdmin() external {\n        require(msg.sender == pendingAdmin);\n        admin = pendingAdmin;\n    }\n\n    function setPause(bool _state) external onlyAdmin {\n        isPaused = _state;\n    }\n    \n    function manageFeeManager(address feeManager, bool _value) external onlyAdmin\n    {\n        feeManagers[feeManager] = _value;\n    }\n    \n    function setFee(bool _stable, uint256 _fee) external onlyFeeManagers {\n        require(_fee <= MAX_FEE, 'fee too high');\n        require(_fee != 0, 'fee must be nonzero');\n        if (_stable) {\n            stableFee = _fee;\n        } else {\n            volatileFee = _fee;\n        }\n    }\n\n    function setFeesOverrides(address _pair, uint256 _fee) external onlyFeeManagers {\n        require(_fee <= MAX_FEE, \"fee too high\");\n        require(_fee != 0, \"fee must be nonzero\");\n        feesOverrides[_pair] = _fee;\n    }\n\n    function getRealFee(address _pair) public view returns(uint256) {\n    \t/// to get base fees, call `stableFee()` or `volatileFee()`\n    \tuint feeOverride = feesOverrides[_pair];\n    \tif(feeOverride > 0) {\n    \t\treturn feeOverride;\n    \t}\n    \telse {\n    \t\treturn IPair(_pair).stable() ? stableFee : volatileFee;\n    \t}\n    }\n\n    function getFee(bool _stable) public view returns(uint256) {\n    \t/// This method, when called by an actual Pair contract itself, would return the real fees.\n    \t/// If simply read, it will show basic fees: stableFee, or the volatileFee.\n    \t/// Please use the `getRealFees` method instead for your Analytics / Dapps / Usecases!\n    \t/// If you want to request a flashloan from any Pair, please query `getRealFee` instead.\n    \taddress caller = msg.sender;\n    \tif(isPair[caller]) {\n    \t\tuint feeOverride = feesOverrides[caller];\n    \t\tif(feeOverride > 0) {\n    \t\t\treturn feeOverride;\n    \t\t}\n    \t\telse {\n                return _stable ? stableFee : volatileFee;\t//non-overridden fee is base fee.\n            } \n    \t} else {\n            return _stable ? stableFee : volatileFee;\t//non-pair callers (caller) see base fee.\n        }\n    }\n\n    function pairCodeHash() external pure returns (bytes32) {\n        return keccak256(type(Pair).creationCode);\n    }\n\n    function getInitializable() external view returns (address, address, bool) {\n        return (_temp0, _temp1, _temp);\n    }\n\n    function createPair(address tokenA, address tokenB, bool stable) external returns (address pair) {\n        require(tokenA != tokenB, 'IA'); // BaseV1: IDENTICAL_ADDRESSES\n        (address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);\n        require(token0 != address(0), 'ZA'); // BaseV1: ZERO_ADDRESS\n        require(getPair[token0][token1][stable] == address(0), 'PE'); // BaseV1: PAIR_EXISTS - single check is sufficient\n        bytes32 salt = keccak256(abi.encodePacked(token0, token1, stable)); // notice salt includes stable as well, 3 parameters\n        (_temp0, _temp1, _temp) = (token0, token1, stable);\n        pair = address(new Pair{salt:salt}());\n        getPair[token0][token1][stable] = pair;\n        getPair[token1][token0][stable] = pair; // populate mapping in the reverse direction\n        allPairs.push(pair);\n        isPair[pair] = true;\n        emit PairCreated(token0, token1, stable, pair, allPairs.length);\n    }\n}\n"
      }
    },
    "settings": {
      "evmVersion": "paris",
      "optimizer": {
        "enabled": true,
        "runs": 10000
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "libraries": {}
    }
  }}