S Price: $0.596721 (-20.21%)
    /

    Contract Diff Checker

    Contract Name:
    Pair

    Contract Source Code:

    File 1 of 1 : Pair

    /**
     *Submitted for verification at basescan.org on 2024-05-16
    */
    
    /**v3.6.0
     *0xd7627edf607c49f525212fc09d650a91a9b222e1
     *Submitted for verification at basescan.org on 2023-10-04
    */
    
    /**0x653ce153d56f749671d42d58b749d02fd9ad3414
     *v3.0.1
     *Submitted for verification at basescan.org on 2023-09-23
    */
    
    /**
     *v3.0.0
     *0xc295f619afc2b8543d91c8970ea4c0726f197250
     *Submitted for verification at basescan.org on 2023-09-19
    */
    
    /**
     *v1.3.11
     *0x8db550677053f2ca3d3bf677cb4e06cc10511958
     *Submitted for verification at FtmScan.com on 2023-02-21
    */
    
    /**
     *v1.1.0
     *0xc9ab1ab21358f4fc36cbbbe27f3b3ead423ec33b
     *Submitted for verification at FtmScan.com on 2022-11-03
    */
    
    /**
     *  EQUALIZER EXCHANGE
     *  The New Liquidity Hub of XChain Decentralized Finance!
     *  https://equalizer.exchange  (Dapp)
     *  https://discord.gg/MaMhbgHMby   (Community)
     *
     *  SPDX-License-Identifier: UNLICENSED
     *
     *
     *  Equalizer v3 Pair Factory
     *  - Equalizer Stableswap 2pool
     *  - Equalizer Classic AMM
     *
     *
     *
     *
     *  Version: v3.0.2
     *  - Allow for universal 0 fees Swaps
     *
     *  Version: v3.0.1
     *  - Introducing 3-Dimensional Fees
     *    - 0° : Constant Fees for all pools
     *    - 1° : Dual Fees - Stablepools vs Volatile pools
     *    - 2° : Fees Overrides: Custom Fees per Pool
     *    - 3° : 🆕 Dynamic Fees Overrides using EⅢ Manangerial Approach
     *              - Fully Dynamic Custom Fees per Pool
     *              - Real Time Variable/Static/Streaming
     *              - EⅢ DEX's Dynamic Fee plugins (https://eliteness.network/e3)
     *                - Volatility-derived Fees adjustment for higher Fee APR
     *                - Auto-adjusting: Low Volume --> Low Fees, attracts trades
     *              - Curve.fi's "A-factor ramp" inspired Trade Fee On/Off Ramps
     *              - Balancer's "Liquidity Bootstrapping Pool" inspired
     *                Quadratic Fees downramps for fine-grained smooth curves, for
     *                New pools/IDO/LGE/Fair Launches via Guru Network's SeedR🌱 plugin
     *
     *
     *  Version: v3.0.0
     *  - Fee Precision upto 1 atto of a token
     *  - Zero-fee Trading for amounts less than PRECISION / getRealFee)
     *    - Example: For BTC/USDT with 0.01% trade fee & decimals 8 & 6,
     *      NO FEES is charged on token amounts traded that are
     *      less than 0.001 USDC or 0.00001 BTC!
     *
     *
     *  Version: 1.3.11 (Deployed at v2.0.0)
     *  - Fees Overrides
     *    - Per Pair Customizable Fees
     *  - Introduce `getRealFees(_pool)` as a new Standard
     *
     *
     *  Version: 1.3.8
     *  - Clarify Fee-Claims are once per veNFT per 7 days per pool
     *  - Real-time Countdown
     *
     *
     *  Version: 1.0.2
     *  - Dual-fee algorithm based on pool stability (correlativity)
     *    - For lower Stableswap fees & higher Volatile pool fee
     *    - Independently adjustable `stableFee` & `volatileFee`
     *
     *
     *
     *  Contributors:
     *   -   Andre Cronje, Solidly.Exchange
     *   -   543 (Sam), ftm.guru, Eliteness.network & Equalizer.exchange
     *
     *
     *
     */
    
    // File: contracts/interfaces/IPairFactory.sol
    
    
    pragma solidity 0.8.9;
    
    interface IPairFactory {
        function isPaused() external view returns (bool);
        function allPairsLength() external view returns (uint);
        function isPair(address pair) external view returns (bool);
        function pairCodeHash() external pure returns (bytes32);
        function getFee(bool _stable) external view returns(uint256);
        function getRealFee(address _pair) external view returns(uint256);
        function feesTakers(address) external view returns(address);
        function getPair(address tokenA, address token, bool stable) external view returns (address);
        function getInitializable() external view returns (address, address, bool);
        function createPair(address tokenA, address tokenB, bool stable) external returns (address pair);
    }
    
    // File: contracts/interfaces/IPairCallee.sol
    
    
    pragma solidity 0.8.9;
    
    interface IPairCallee {
        function hook(address sender, uint amount0, uint amount1, bytes calldata data) external;
    }
    
    // File: contracts/interfaces/IFeeManager.sol
    
    
    pragma solidity 0.8.9;
    
    interface IFeeManager {
        function getFee(address pool) external view returns(uint256);
    }
    
    // File: contracts/interfaces/IPairCallee.sol
    
    
    pragma solidity 0.8.9;
    
    interface IPair {
        function stable() external view returns (bool _s);
    }
    
    // File: contracts/interfaces/IERC20.sol
    
    
    pragma solidity 0.8.9;
    
    interface IERC20 {
        function totalSupply() external view returns (uint256);
        function transfer(address recipient, uint amount) external returns (bool);
        function decimals() external view returns (uint8);
        function symbol() external view returns (string memory);
        function name() external view returns (string memory);
        function balanceOf(address) external view returns (uint);
        function transferFrom(address sender, address recipient, uint amount) external returns (bool);
        function allowance(address owner, address spender) external view returns (uint);
        function approve(address spender, uint value) external returns (bool);
    
        event Transfer(address indexed from, address indexed to, uint value);
        event Approval(address indexed owner, address indexed spender, uint value);
    }
    
    // File: contracts/libraries/Math.sol
    
    
    pragma solidity 0.8.9;
    
    library Math {
        function max(uint a, uint b) internal pure returns (uint) {
            return a >= b ? a : b;
        }
        function min(uint a, uint b) internal pure returns (uint) {
            return a < b ? a : b;
        }
        function sqrt(uint y) internal pure returns (uint z) {
            if (y > 3) {
                z = y;
                uint x = y / 2 + 1;
                while (x < z) {
                    z = x;
                    x = (y / x + x) / 2;
                }
            } else if (y != 0) {
                z = 1;
            }
        }
        function cbrt(uint256 n) internal pure returns (uint256) { unchecked {
            uint256 x = 0;
            for (uint256 y = 1 << 255; y > 0; y >>= 3) {
                x <<= 1;
                uint256 z = 3 * x * (x + 1) + 1;
                if (n / y >= z) {
                    n -= y * z;
                    x += 1;
                }
            }
            return x;
        }}
    }
    
    // File: @openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol
    
    
    // OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)
    
    pragma solidity ^0.8.1;
    
    /**
     * @dev Collection of functions related to the address type
     */
    library AddressUpgradeable {
        /**
         * @dev Returns true if `account` is a contract.
         *
         * [IMPORTANT]
         * ====
         * It is unsafe to assume that an address for which this function returns
         * false is an externally-owned account (EOA) and not a contract.
         *
         * Among others, `isContract` will return false for the following
         * types of addresses:
         *
         *  - an externally-owned account
         *  - a contract in construction
         *  - an address where a contract will be created
         *  - an address where a contract lived, but was destroyed
         * ====
         *
         * [IMPORTANT]
         * ====
         * You shouldn't rely on `isContract` to protect against flash loan attacks!
         *
         * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
         * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
         * constructor.
         * ====
         */
        function isContract(address account) internal view returns (bool) {
            // This method relies on extcodesize/address.code.length, which returns 0
            // for contracts in construction, since the code is only stored at the end
            // of the constructor execution.
    
            return account.code.length > 0;
        }
    
        /**
         * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
         * `recipient`, forwarding all available gas and reverting on errors.
         *
         * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
         * of certain opcodes, possibly making contracts go over the 2300 gas limit
         * imposed by `transfer`, making them unable to receive funds via
         * `transfer`. {sendValue} removes this limitation.
         *
         * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
         *
         * IMPORTANT: because control is transferred to `recipient`, care must be
         * taken to not create reentrancy vulnerabilities. Consider using
         * {ReentrancyGuard} or the
         * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
         */
        function sendValue(address payable recipient, uint256 amount) internal {
            require(address(this).balance >= amount, "Address: insufficient balance");
    
            (bool success, ) = recipient.call{value: amount}("");
            require(success, "Address: unable to send value, recipient may have reverted");
        }
    
        /**
         * @dev Performs a Solidity function call using a low level `call`. A
         * plain `call` is an unsafe replacement for a function call: use this
         * function instead.
         *
         * If `target` reverts with a revert reason, it is bubbled up by this
         * function (like regular Solidity function calls).
         *
         * Returns the raw returned data. To convert to the expected return value,
         * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
         *
         * Requirements:
         *
         * - `target` must be a contract.
         * - calling `target` with `data` must not revert.
         *
         * _Available since v3.1._
         */
        function functionCall(address target, bytes memory data) internal returns (bytes memory) {
            return functionCall(target, data, "Address: low-level call failed");
        }
    
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
         * `errorMessage` as a fallback revert reason when `target` reverts.
         *
         * _Available since v3.1._
         */
        function functionCall(
            address target,
            bytes memory data,
            string memory errorMessage
        ) internal returns (bytes memory) {
            return functionCallWithValue(target, data, 0, errorMessage);
        }
    
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
         * but also transferring `value` wei to `target`.
         *
         * Requirements:
         *
         * - the calling contract must have an ETH balance of at least `value`.
         * - the called Solidity function must be `payable`.
         *
         * _Available since v3.1._
         */
        function functionCallWithValue(
            address target,
            bytes memory data,
            uint256 value
        ) internal returns (bytes memory) {
            return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
        }
    
        /**
         * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
         * with `errorMessage` as a fallback revert reason when `target` reverts.
         *
         * _Available since v3.1._
         */
        function functionCallWithValue(
            address target,
            bytes memory data,
            uint256 value,
            string memory errorMessage
        ) internal returns (bytes memory) {
            require(address(this).balance >= value, "Address: insufficient balance for call");
            require(isContract(target), "Address: call to non-contract");
    
            (bool success, bytes memory returndata) = target.call{value: value}(data);
            return verifyCallResult(success, returndata, errorMessage);
        }
    
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
         * but performing a static call.
         *
         * _Available since v3.3._
         */
        function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
            return functionStaticCall(target, data, "Address: low-level static call failed");
        }
    
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
         * but performing a static call.
         *
         * _Available since v3.3._
         */
        function functionStaticCall(
            address target,
            bytes memory data,
            string memory errorMessage
        ) internal view returns (bytes memory) {
            require(isContract(target), "Address: static call to non-contract");
    
            (bool success, bytes memory returndata) = target.staticcall(data);
            return verifyCallResult(success, returndata, errorMessage);
        }
    
        /**
         * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
         * revert reason using the provided one.
         *
         * _Available since v4.3._
         */
        function verifyCallResult(
            bool success,
            bytes memory returndata,
            string memory errorMessage
        ) internal pure returns (bytes memory) {
            if (success) {
                return returndata;
            } else {
                // Look for revert reason and bubble it up if present
                if (returndata.length > 0) {
                    // The easiest way to bubble the revert reason is using memory via assembly
                    /// @solidity memory-safe-assembly
                    assembly {
                        let returndata_size := mload(returndata)
                        revert(add(32, returndata), returndata_size)
                    }
                } else {
                    revert(errorMessage);
                }
            }
        }
    }
    
    // File: @openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol
    
    
    // OpenZeppelin Contracts (last updated v4.7.0) (proxy/utils/Initializable.sol)
    
    pragma solidity ^0.8.2;
    
    
    /**
     * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
     * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
     * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
     * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
     *
     * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
     * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
     * case an upgrade adds a module that needs to be initialized.
     *
     * For example:
     *
     * [.hljs-theme-light.nopadding]
     * ```
     * contract MyToken is ERC20Upgradeable {
     *     function initialize() initializer public {
     *         __ERC20_init("MyToken", "MTK");
     *     }
     * }
     * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
     *     function initializeV2() reinitializer(2) public {
     *         __ERC20Permit_init("MyToken");
     *     }
     * }
     * ```
     *
     * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
     * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
     *
     * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
     * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
     *
     * [CAUTION]
     * ====
     * Avoid leaving a contract uninitialized.
     *
     * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
     * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
     * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
     *
     * [.hljs-theme-light.nopadding]
     * ```
     * /// @custom:oz-upgrades-unsafe-allow constructor
     * constructor() {
     *     _disableInitializers();
     * }
     * ```
     * ====
     */
    abstract contract Initializable {
        /**
         * @dev Indicates that the contract has been initialized.
         * @custom:oz-retyped-from bool
         */
        uint8 private _initialized;
    
        /**
         * @dev Indicates that the contract is in the process of being initialized.
         */
        bool private _initializing;
    
        /**
         * @dev Triggered when the contract has been initialized or reinitialized.
         */
        event Initialized(uint8 version);
    
        /**
         * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
         * `onlyInitializing` functions can be used to initialize parent contracts. Equivalent to `reinitializer(1)`.
         */
        modifier initializer() {
            bool isTopLevelCall = !_initializing;
            require(
                (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
                "Initializable: contract is already initialized"
            );
            _initialized = 1;
            if (isTopLevelCall) {
                _initializing = true;
            }
            _;
            if (isTopLevelCall) {
                _initializing = false;
                emit Initialized(1);
            }
        }
    
        /**
         * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
         * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
         * used to initialize parent contracts.
         *
         * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original
         * initialization step. This is essential to configure modules that are added through upgrades and that require
         * initialization.
         *
         * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
         * a contract, executing them in the right order is up to the developer or operator.
         */
        modifier reinitializer(uint8 version) {
            require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
            _initialized = version;
            _initializing = true;
            _;
            _initializing = false;
            emit Initialized(version);
        }
    
        /**
         * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
         * {initializer} and {reinitializer} modifiers, directly or indirectly.
         */
        modifier onlyInitializing() {
            require(_initializing, "Initializable: contract is not initializing");
            _;
        }
    
        /**
         * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
         * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
         * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
         * through proxies.
         */
        function _disableInitializers() internal virtual {
            require(!_initializing, "Initializable: contract is initializing");
            if (_initialized < type(uint8).max) {
                _initialized = type(uint8).max;
                emit Initialized(type(uint8).max);
            }
        }
    }
    
    // File: contracts/PairFees.sol
    
    
    pragma solidity 0.8.9;
    
    
    
    /**
    * @title Pair Fees
    * @notice 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
    */
    
    contract PairFees is Initializable {
    
        address internal pair; // The pair it is bonded to
        address internal token0; // token0 of pair, saved localy and statically for gas optimization
        address internal token1; // Token1 of pair, saved localy and statically for gas optimization
    
        function initialize(address _token0, address _token1) public initializer {
            pair = msg.sender;
            token0 = _token0;
            token1 = _token1;
        }
    
        function _safeTransfer(address token,address to,uint256 value) internal {
            require(token.code.length > 0, "PairFees: invalid token");
            (bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.transfer.selector, to, value));
            require(success && (data.length == 0 || abi.decode(data, (bool))), "PairFees: transfer failed");
        }
    
        // Allow the pair to transfer fees to users
        function claimFeesFor(address recipient, uint amount0, uint amount1) external {
            require(msg.sender == pair, "Only pair contract can call");
            // forfeit deficits from Fee-on-Transfer tokens
            uint _bal0 = IERC20(token0).balanceOf(address(this));
            uint _bal1 = IERC20(token1).balanceOf(address(this));
            if (amount0 > _bal0) amount0 = _bal0;
            if (amount1 > _bal1) amount1 = _bal1;
            if (amount0 > 0) _safeTransfer(token0, recipient, amount0);
            if (amount1 > 0) _safeTransfer(token1, recipient, amount1);
        }
    }
    
    // File: contracts/Pair.sol
    
    
    pragma solidity 0.8.9;
    
    
    
    
    
    
    
    contract Pair is Initializable {
    
        string public name;
        string public symbol;
        uint8 public constant decimals = 18;
    
        /// @notice Used to denote stable or volatile pair, not immutable since construction happens in the initialize method for CREATE2 deterministic addresses
        bool public stable;
    
        uint256 public totalSupply;
    
        mapping(address => mapping (address => uint)) public allowance;
        mapping(address => uint) public balanceOf;
    
        bytes32 internal DOMAIN_SEPARATOR;
        /// @dev keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
        bytes32 internal constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
        mapping(address => uint) public nonces;
    
        uint256 internal constant MINIMUM_LIQUIDITY = 10**3;
    
        address public token0;
        address public token1;
        address public fees;
        address public factory;
    
        // Structure to capture time period obervations every 30 minutes, used for local oracles
        struct Observation {
            uint timestamp;
            uint reserve0Cumulative;
            uint reserve1Cumulative;
        }
    
        // Capture oracle reading every 30 minutes
        uint constant periodSize = 1800;
    
        Observation[] public observations;
    
        uint internal decimals0;
        uint internal decimals1;
    
        uint public reserve0;
        uint public reserve1;
        uint public blockTimestampLast;
    
        uint public reserve0CumulativeLast;
        uint public reserve1CumulativeLast;
    
        // index0 and index1 are used to accumulate fees, this is split out from normal trades to keep the swap "clean"
        // this further allows LP holders to easily claim fees for tokens they have/staked
        uint public index0;
        uint public index1;
    
        // position assigned to each LP to track their current index0 & index1 vs the global position
        mapping(address => uint) public supplyIndex0;
        mapping(address => uint) public supplyIndex1;
    
        // tracks the amount of unclaimed, but claimable tokens off of fees for token0 and token1
        mapping(address => uint) public claimable0;
        mapping(address => uint) public claimable1;
    
        /// @dev simple re-entrancy check
        bool internal _locked;
    
        event Fees(address indexed sender, uint amount0, uint amount1);
        event Mint(address indexed sender, uint amount0, uint amount1);
        event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);
        event Swap(
            address indexed sender,
            uint amount0In,
            uint amount1In,
            uint amount0Out,
            uint amount1Out,
            address indexed to
        );
        event Sync(uint reserve0, uint reserve1);
        event Claim(address indexed sender, address indexed recipient, uint amount0, uint amount1);
    
        event Transfer(address indexed from, address indexed to, uint amount);
        event Approval(address indexed owner, address indexed spender, uint amount);
    
        modifier lock() {
            require(!_locked, "No re-entrancy");
            _locked = true;
            _;
            _locked = false;
        }
    
        function initialize() public initializer {
            factory = msg.sender;
            (address _token0, address _token1, bool _stable) = IPairFactory(msg.sender).getInitializable();
            (token0, token1, stable) = (_token0, _token1, _stable);
            PairFees pairFees = new PairFees();
            pairFees.initialize(_token0, _token1);
            fees = address(pairFees);
    
            if (_stable) {
                name = string(abi.encodePacked("Equalizer Stableswap 2pool - ", IERC20(_token0).name(), " paired with ", IERC20(_token1).name()));
                symbol = string(abi.encodePacked("s-", IERC20(_token0).symbol(), "/", IERC20(_token1).symbol()));
            } else {
                name = string(abi.encodePacked("Equalizer Classic AMM - ", IERC20(_token0).name(), " paired with ", IERC20(_token1).name()));
                symbol = string(abi.encodePacked("v-", IERC20(_token0).symbol(), "/", IERC20(_token1).symbol()));
            }
    
            decimals0 = 10**IERC20(_token0).decimals();
            decimals1 = 10**IERC20(_token1).decimals();
    
            observations.push(Observation(block.timestamp, 0, 0));
        }
    
        function observationLength() external view returns (uint) {
            return observations.length;
        }
    
        function lastObservation() public view returns (Observation memory) {
            return observations[observations.length-1];
        }
    
        function metadata() external view returns (uint dec0, uint dec1, uint r0, uint r1, bool st, address t0, address t1) {
            return (decimals0, decimals1, reserve0, reserve1, stable, token0, token1);
        }
    
        function tokens() external view returns (address, address) {
            return (token0, token1);
        }
    
        /// @dev claim accumulated but unclaimed fees (viewable via claimable0 and claimable1)
        function claimFees() external returns (uint claimed0, uint claimed1) {
            _updateFor(msg.sender);
    
            claimed0 = claimable0[msg.sender];
            claimed1 = claimable1[msg.sender];
    
            if (claimed0 > 0 || claimed1 > 0) {
                claimable0[msg.sender] = 0;
                claimable1[msg.sender] = 0;
    
                PairFees(fees).claimFeesFor(msg.sender, claimed0, claimed1);
    
                emit Claim(msg.sender, msg.sender, claimed0, claimed1);
            }
        }
    
        /// @dev Accrue fees on token0
        function _update0(uint amount) internal {
            _safeTransfer(token0, fees, amount); // transfer the fees out to PairFees
            uint256 _ratio = amount * 1e18 / totalSupply; // 1e18 adjustment is removed during claim
            if (_ratio > 0) {
                index0 += _ratio;
            }
            emit Fees(msg.sender, amount, 0);
        }
    
        /// @dev Accrue fees on token1
        function _update1(uint amount) internal {
            _safeTransfer(token1, fees, amount);
            uint256 _ratio = amount * 1e18 / totalSupply;
            if (_ratio > 0) {
                index1 += _ratio;
            }
            emit Fees(msg.sender, 0, amount);
        }
    
        /**
         * @notice This function must be called on any balance changes, otherwise can be used to infinitely claim fees
         * Fees are segregated from core funds, so fees can never put liquidity at risk
         */
        function _updateFor(address recipient) internal {
            uint _supplied = balanceOf[recipient]; // get LP balance of `recipient`
            if (_supplied > 0) {
                uint _supplyIndex0 = supplyIndex0[recipient]; // get last adjusted index0 for recipient
                uint _supplyIndex1 = supplyIndex1[recipient];
                uint _index0 = index0; // get global index0 for accumulated fees
                uint _index1 = index1;
                supplyIndex0[recipient] = _index0; // update user current position to global position
                supplyIndex1[recipient] = _index1;
                uint _delta0 = _index0 - _supplyIndex0; // see if there is any difference that need to be accrued
                uint _delta1 = _index1 - _supplyIndex1;
                if (_delta0 > 0) {
                    uint _share = _supplied * _delta0 / 1e18; // add accrued difference for each supplied token
                    claimable0[recipient] += _share;
                }
                if (_delta1 > 0) {
                    uint _share = _supplied * _delta1 / 1e18;
                    claimable1[recipient] += _share;
                }
            } else {
                supplyIndex0[recipient] = index0; // new users are set to the default global state
                supplyIndex1[recipient] = index1;
            }
        }
    
        function getReserves() public view returns (uint _reserve0, uint _reserve1, uint _blockTimestampLast) {
            _reserve0 = reserve0;
            _reserve1 = reserve1;
            _blockTimestampLast = blockTimestampLast;
        }
    
        /// @dev update reserves and, on the first call per block, price accumulators
        function _update(uint balance0, uint balance1, uint _reserve0, uint _reserve1) internal {
            uint blockTimestamp = block.timestamp;
            uint timeElapsed = blockTimestamp - blockTimestampLast; // overflow is desired
            if (timeElapsed > 0 && _reserve0 != 0 && _reserve1 != 0) {
                reserve0CumulativeLast += _reserve0 * timeElapsed;
                reserve1CumulativeLast += _reserve1 * timeElapsed;
            }
    
            Observation memory _point = lastObservation();
            timeElapsed = blockTimestamp - _point.timestamp; // compare the last observation with current timestamp, if greater than 30 minutes, record a new event
            if (timeElapsed > periodSize) {
                observations.push(Observation(blockTimestamp, reserve0CumulativeLast, reserve1CumulativeLast));
            }
            reserve0 = balance0;
            reserve1 = balance1;
            blockTimestampLast = blockTimestamp;
            emit Sync(reserve0, reserve1);
        }
    
        /// @dev produces the cumulative price using counterfactuals to save gas and avoid a call to sync.
        function currentCumulativePrices() public view returns (uint reserve0Cumulative, uint reserve1Cumulative, uint blockTimestamp) {
            blockTimestamp = block.timestamp;
            reserve0Cumulative = reserve0CumulativeLast;
            reserve1Cumulative = reserve1CumulativeLast;
    
            // if time has elapsed since the last update on the pair, mock the accumulated price values
            (uint _reserve0, uint _reserve1, uint _blockTimestampLast) = getReserves();
            if (_blockTimestampLast != blockTimestamp) {
                // subtraction overflow is desired
                uint timeElapsed = blockTimestamp - _blockTimestampLast;
                reserve0Cumulative += _reserve0 * timeElapsed;
                reserve1Cumulative += _reserve1 * timeElapsed;
            }
        }
    
        /// @dev gives the current twap price measured from amountIn * tokenIn gives amountOut
        function current(address tokenIn, uint amountIn) external view returns (uint amountOut) {
            Observation memory _observation = lastObservation();
            (uint reserve0Cumulative, uint reserve1Cumulative,) = currentCumulativePrices();
            if (block.timestamp == _observation.timestamp) {
                _observation = observations[observations.length-2];
            }
    
            uint timeElapsed = block.timestamp - _observation.timestamp;
            uint _reserve0 = (reserve0Cumulative - _observation.reserve0Cumulative) / timeElapsed;
            uint _reserve1 = (reserve1Cumulative - _observation.reserve1Cumulative) / timeElapsed;
            amountOut = _getAmountOut(amountIn, tokenIn, _reserve0, _reserve1);
        }
    
        /// @dev as per `current`, however allows user configured granularity, up to the full window size
        function quote(address tokenIn, uint amountIn, uint granularity) external view returns (uint amountOut) {
            uint [] memory _prices = sample(tokenIn, amountIn, granularity, 1);
            uint priceAverageCumulative;
            for (uint i = 0; i < _prices.length; i++) {
                priceAverageCumulative += _prices[i];
            }
            return priceAverageCumulative / granularity;
        }
    
        /// @dev returns a memory set of twap prices
        function prices(address tokenIn, uint amountIn, uint points) external view returns (uint[] memory) {
            return sample(tokenIn, amountIn, points, 1);
        }
    
        function sample(address tokenIn, uint amountIn, uint points, uint window) public view returns (uint[] memory) {
            uint[] memory _prices = new uint[](points);
    
            uint length = observations.length-1;
            uint i = length - (points * window);
            uint nextIndex = 0;
            uint index = 0;
    
            for (; i < length; i+=window) {
                nextIndex = i + window;
                uint timeElapsed = observations[nextIndex].timestamp - observations[i].timestamp;
                uint _reserve0 = (observations[nextIndex].reserve0Cumulative - observations[i].reserve0Cumulative) / timeElapsed;
                uint _reserve1 = (observations[nextIndex].reserve1Cumulative - observations[i].reserve1Cumulative) / timeElapsed;
                _prices[index] = _getAmountOut(amountIn, tokenIn, _reserve0, _reserve1);
                // index < length; length cannot overflow
                unchecked {
                    index = index + 1;
                }
            }
            return _prices;
        }
    
        /**
         * @notice this low-level function should be called by addLiquidity functions in Router.sol, which performs important safety checks
         * standard uniswap v2 implementation
         */
        function mint(address to) external lock returns (uint liquidity) {
            (uint _reserve0, uint _reserve1) = (reserve0, reserve1);
            uint _balance0 = IERC20(token0).balanceOf(address(this));
            uint _balance1 = IERC20(token1).balanceOf(address(this));
            uint _amount0 = _balance0 - _reserve0;
            uint _amount1 = _balance1 - _reserve1;
    
            uint _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee
            if (_totalSupply == 0) {
                liquidity = Math.sqrt(_amount0 * _amount1) - MINIMUM_LIQUIDITY;
                _mint(address(0), MINIMUM_LIQUIDITY); // permanently lock the first MINIMUM_LIQUIDITY tokens
            } else {
                liquidity = Math.min(_amount0 * _totalSupply / _reserve0, _amount1 * _totalSupply / _reserve1);
            }
            require(liquidity > 0, "ILM"); // Pair: INSUFFICIENT_LIQUIDITY_MINTED
            _mint(to, liquidity);
    
            _update(_balance0, _balance1, _reserve0, _reserve1);
            emit Mint(msg.sender, _amount0, _amount1);
        }
    
        /**
         * @notice this low-level function should be called from a contract which performs important safety checks
         * standard uniswap v2 implementation
         */
        function burn(address to) external lock returns (uint amount0, uint amount1) {
            (uint _reserve0, uint _reserve1) = (reserve0, reserve1);
            (address _token0, address _token1) = (token0, token1);
            uint _balance0 = IERC20(_token0).balanceOf(address(this));
            uint _balance1 = IERC20(_token1).balanceOf(address(this));
            uint _liquidity = balanceOf[address(this)];
    
            uint _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee
            amount0 = _liquidity * _balance0 / _totalSupply; // using balances ensures pro-rata distribution
            amount1 = _liquidity * _balance1 / _totalSupply; // using balances ensures pro-rata distribution
            require(amount0 > 0 && amount1 > 0, "ILB"); // Pair: INSUFFICIENT_LIQUIDITY_BURNED
            _burn(address(this), _liquidity);
            _safeTransfer(_token0, to, amount0);
            _safeTransfer(_token1, to, amount1);
            _balance0 = IERC20(_token0).balanceOf(address(this));
            _balance1 = IERC20(_token1).balanceOf(address(this));
    
            _update(_balance0, _balance1, _reserve0, _reserve1);
            emit Burn(msg.sender, amount0, amount1, to);
        }
    
        /// @dev this low-level function should be called from a contract which performs important safety checks
        function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external lock {
            require(!IPairFactory(factory).isPaused());
            require(amount0Out > 0 || amount1Out > 0, "IOA"); // Pair: INSUFFICIENT_OUTPUT_AMOUNT
            (uint _reserve0, uint _reserve1) =  (reserve0, reserve1);
            require(amount0Out < _reserve0 && amount1Out < _reserve1, "IL"); // Pair: INSUFFICIENT_LIQUIDITY
    
            uint _balance0;
            uint _balance1;
            { // scope for _token{0,1}, avoids stack too deep errors
            (address _token0, address _token1) = (token0, token1);
            require(to != _token0 && to != _token1, "IT"); // Pair: INVALID_TO
            if (amount0Out > 0) _safeTransfer(_token0, to, amount0Out); // optimistically transfer tokens
            if (amount1Out > 0) _safeTransfer(_token1, to, amount1Out); // optimistically transfer tokens
            if (data.length > 0) IPairCallee(to).hook(msg.sender, amount0Out, amount1Out, data); // callback, used for flash loans
            _balance0 = IERC20(_token0).balanceOf(address(this));
            _balance1 = IERC20(_token1).balanceOf(address(this));
            }
            uint amount0In = _balance0 > _reserve0 - amount0Out ? _balance0 - (_reserve0 - amount0Out) : 0;
            uint amount1In = _balance1 > _reserve1 - amount1Out ? _balance1 - (_reserve1 - amount1Out) : 0;
            require(amount0In > 0 || amount1In > 0, "IIA"); // Pair: INSUFFICIENT_INPUT_AMOUNT
            { // scope for reserve{0,1}Adjusted, avoids stack too deep errors
            (address _token0, address _token1) = (token0, token1);
            if (amount0In > 0) _update0(amount0In * IPairFactory(factory).getRealFee(address(this)) / 1e18); // accrue fees for token0 and move them out of pool
            if (amount1In > 0) _update1(amount1In * IPairFactory(factory).getRealFee(address(this)) / 1e18); // accrue fees for token1 and move them out of pool
            _balance0 = IERC20(_token0).balanceOf(address(this)); // since we removed tokens, we need to reconfirm balances, can also simply use previous balance - amountIn/ 10000 (1e18 in V3), but doing balanceOf again as safety check
            _balance1 = IERC20(_token1).balanceOf(address(this));
            // The curve, either x3y+y3x for stable pools, or x*y for volatile pools
            require(_k(_balance0, _balance1) >= _k(_reserve0, _reserve1), "K"); // Pair: K
            }
    
            _update(_balance0, _balance1, _reserve0, _reserve1);
            emit Swap(msg.sender, amount0In, amount1In, amount0Out, amount1Out, to);
        }
    
        /// @dev force balances to match reserves
        function skim(address to) external lock {
        	address _ft = IPairFactory(factory).feesTakers(address(this));
        	if(_ft != address(0)) { to = _ft; }
            (address _token0, address _token1) = (token0, token1);
            _safeTransfer(_token0, to, IERC20(_token0).balanceOf(address(this)) - (reserve0));
            _safeTransfer(_token1, to, IERC20(_token1).balanceOf(address(this)) - (reserve1));
        }
    
        /// @dev force reserves to match balances
        function sync() external lock {
            _update(IERC20(token0).balanceOf(address(this)), IERC20(token1).balanceOf(address(this)), reserve0, reserve1);
        }
    
        function _f(uint x0, uint y) internal pure returns (uint) {
            return x0*(y*y/1e18*y/1e18)/1e18+(x0*x0/1e18*x0/1e18)*y/1e18;
        }
    
        function _d(uint x0, uint y) internal pure returns (uint) {
            return 3*x0*(y*y/1e18)/1e18+(x0*x0/1e18*x0/1e18);
        }
    
        function _get_y(uint x0, uint xy, uint y) internal pure returns (uint) {
            for (uint i = 0; i < 255; i++) {
                uint y_prev = y;
                uint k = _f(x0, y);
                if (k < xy) {
                    uint dy = (xy - k)*1e18/_d(x0, y);
                    y = y + dy;
                } else {
                    uint dy = (k - xy)*1e18/_d(x0, y);
                    y = y - dy;
                }
                if (y > y_prev) {
                    if (y - y_prev <= 1) {
                        return y;
                    }
                } else {
                    if (y_prev - y <= 1) {
                        return y;
                    }
                }
            }
            return y;
        }
    
        function getAmountOut(uint amountIn, address tokenIn) external view returns (uint) {
            (uint _reserve0, uint _reserve1) = (reserve0, reserve1);
            amountIn -= amountIn * IPairFactory(factory).getRealFee(address(this)) / 1e18; // remove fee from amount received
            return _getAmountOut(amountIn, tokenIn, _reserve0, _reserve1);
        }
    
        function _getAmountOut(uint amountIn, address tokenIn, uint _reserve0, uint _reserve1) internal view returns (uint) {
            if (stable) {
                uint xy =  _k(_reserve0, _reserve1);
                _reserve0 = _reserve0 * 1e18 / decimals0;
                _reserve1 = _reserve1 * 1e18 / decimals1;
                (uint reserveA, uint reserveB) = tokenIn == token0 ? (_reserve0, _reserve1) : (_reserve1, _reserve0);
                amountIn = tokenIn == token0 ? amountIn * 1e18 / decimals0 : amountIn * 1e18 / decimals1;
                uint y = reserveB - _get_y(amountIn+reserveA, xy, reserveB);
                return y * (tokenIn == token0 ? decimals1 : decimals0) / 1e18;
            } else {
                (uint reserveA, uint reserveB) = tokenIn == token0 ? (_reserve0, _reserve1) : (_reserve1, _reserve0);
                return amountIn * reserveB / (reserveA + amountIn);
            }
        }
    
        function _k(uint x, uint y) internal view returns (uint) {
            if (stable) {
                uint _x = x * 1e18 / decimals0;
                uint _y = y * 1e18 / decimals1;
                uint _a = (_x * _y) / 1e18;
                uint _b = ((_x * _x) / 1e18 + (_y * _y) / 1e18);
                return _a * _b / 1e18;  // x3y+y3x >= k
            } else {
                return x * y; // xy >= k
            }
        }
    
        function _mint(address dst, uint amount) internal {
            _updateFor(dst); // balances must be updated on mint/burn/transfer
            totalSupply += amount;
            balanceOf[dst] += amount;
            emit Transfer(address(0), dst, amount);
        }
    
        function _burn(address dst, uint amount) internal {
            _updateFor(dst);
            totalSupply -= amount;
            balanceOf[dst] -= amount;
            emit Transfer(dst, address(0), amount);
        }
    
        function approve(address spender, uint amount) external returns (bool) {
            allowance[msg.sender][spender] = amount;
    
            emit Approval(msg.sender, spender, amount);
            return true;
        }
    
        function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external {
            require(deadline >= block.timestamp, "Pair: EXPIRED");
            DOMAIN_SEPARATOR = keccak256(
                abi.encode(
                    keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
                    keccak256(bytes(name)),
                    keccak256(bytes("1")),
                    block.chainid,
                    address(this)
                )
            );
            bytes32 digest = keccak256(
                abi.encodePacked(
                    "\x19\x01",
                    DOMAIN_SEPARATOR,
                    keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline))
                )
            );
            address recoveredAddress = ecrecover(digest, v, r, s);
            require(recoveredAddress != address(0) && recoveredAddress == owner, "Pair: INVALID_SIGNATURE");
            allowance[owner][spender] = value;
    
            emit Approval(owner, spender, value);
        }
    
        function transfer(address dst, uint amount) external returns (bool) {
            _transferTokens(msg.sender, dst, amount);
            return true;
        }
    
        function transferFrom(address src, address dst, uint amount) external returns (bool) {
            address spender = msg.sender;
            uint spenderAllowance = allowance[src][spender];
    
            if (spender != src && spenderAllowance != type(uint).max) {
                uint newAllowance = spenderAllowance - amount;
                allowance[src][spender] = newAllowance;
    
                emit Approval(src, spender, newAllowance);
            }
    
            _transferTokens(src, dst, amount);
            return true;
        }
    
        function _transferTokens(address src, address dst, uint amount) internal {
            _updateFor(src); // update fee position for src
            _updateFor(dst); // update fee position for dst
    
            balanceOf[src] -= amount;
            balanceOf[dst] += amount;
    
            emit Transfer(src, dst, amount);
        }
    
        function _safeTransfer(address token,address to,uint256 value) internal {
            require(token.code.length > 0, "Pair: invalid token");
            (bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.transfer.selector, to, value));
            require(success && (data.length == 0 || abi.decode(data, (bool))), "Pair: transfer failed");
        }
    
    }
    
    // File: contracts/factories/PairFactory.sol
    
    
    pragma solidity 0.8.9;
    
    
    
    contract PairFactory is Initializable {
    
        bool public isPaused;
        address public pauser;
        address public pendingPauser;
    
        uint256 public stableFee;
        uint256 public volatileFee;
        address public feeManager;
        address public pendingFeeManager;
    
        mapping(address => mapping(address => mapping(bool => address))) public getPair;
        address[] public allPairs;
        mapping(address => bool) public isPair; // simplified check if its a pair, given that `stable` flag might not be available in peripherals
    
        address internal _temp0;
        address internal _temp1;
        bool internal _temp;
    
    
        // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
        // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
        // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
        // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
        // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
    
    	/// VARIBALES ARE STATEFUL !  DONT MESS WITH THEM SLOTS !!
    	/// ADDITIONAL SLOTS ATTACHED TO TAIL -- DONT DELETE ANY VARIABLES, ONLY ADD NEW ONES TO THE TAIL!!!
    	/// (There are a limited number of slots! (almost infinte, dont worry;))
    	/// v1.3.11
    	//(Using a new variable instead at Tail to not cause slot collision, as this contract will be used as Equalizer's PairFactory implementation)
    	uint256 public constant MAX_FEE = 1 ether;
        mapping(address => uint256) public feesOverrideStatic;
        mapping(address => address) public feesOverrideDynamic;
        mapping(address => address) public feesTakers;
    
    
    
        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *ALL STATEFUL STUFF ABOVE!* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
         * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
         * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
         * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
         * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
         * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
         * Such events, much eventful
         * @notice Events are stateless, ordering doesn't matter.
         */
        event PairCreated(address indexed token0, address indexed token1, bool stable, address pair, uint);
    
    
        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
         * wow functions, very fun
         * @notice Functions are stateless, ordering doesn't matter.
         */
    
        function initialize() public initializer {
            pauser = msg.sender;
            isPaused = false;
            feeManager = msg.sender;
            stableFee = 0.0002 ether;
            volatileFee = 0.01 ether;
        }
    
        function allPairsLength() external view returns (uint) {
            return allPairs.length;
        }
    
        function setPauser(address _pauser) external {
            require(msg.sender == pauser, "PairFactory: not a pauser");
            pendingPauser = _pauser;
        }
    
        function acceptPauser() external {
            require(msg.sender == pendingPauser, "PairFactory: not a pendingPauser");
            pauser = pendingPauser;
        }
    
        function setPause(bool _state) external {
            require(msg.sender == pauser, "PairFactory: not a pauser");
            isPaused = _state;
        }
    
        function setFeeManager(address _feeManager) external {
            require(msg.sender == feeManager, "not fee manager");
            pendingFeeManager = _feeManager;
        }
    
        function acceptFeeManager() external {
            require(msg.sender == pendingFeeManager, "not pending fee manager");
            feeManager = pendingFeeManager;
        }
    
        function setFeeDefaults(uint256 _stable, uint256 _volatile) external {
            require(msg.sender == feeManager, "not fee manager");
            require(_stable < MAX_FEE, "fee too high");
            require(_volatile < MAX_FEE, "fee too high");
            //require(_volatile * _stable != 0, "fee must be nonzero");
            stableFee = _stable;
            volatileFee = _volatile;
        }
    
        function setFeesOverrideStatic(address _pair, uint256 _fee) external {
            require(msg.sender == feeManager, "not fee manager");
            require(_fee < MAX_FEE, "fee too high");
            //require(_fee != 0, "fee must be nonzero");
            feesOverrideStatic[_pair] = _fee;
        }
    
        function setFeesOverrideDynamic(address _pair, address _feeManager) external {
            require(msg.sender == feeManager, "not fee manager");
            require(AddressUpgradeable.isContract(_feeManager), "invalid fee manager");
            uint _fee = IFeeManager(_feeManager).getFee(_pair);
            require(_fee < MAX_FEE, "fee too high");
            //require(_fee != 0, "fee must be nonzero");
            feesOverrideDynamic[_pair] = _feeManager;
        }
    
        function setFeesTakers(address _p, address _t) external {
            require(msg.sender == feeManager, "not fee manager");
            feesTakers[_p] = _t;
        }
    
        function getRealFee(address _pair) public view returns(uint256) {
        	/// to get base fees, call `stableFee()` or `volatileFee()`
        	uint _fos = feesOverrideStatic[ _pair ];
        	if( _fos > 0 ) {
        		return _fos;
        	}
        	address _fod = feesOverrideDynamic[_pair];
        	if( _fod != address(0) ) {
        		return Math.min(
        			Math.max(
        				1,
        				IFeeManager(_fod).getFee(_pair)
        			),
        			1 ether - 1
        		);
        	}
        	return IPair(_pair).stable()
        		? stableFee
        		: volatileFee
        	;
        }
    
        /// This method was retired in v3.0.1
        /// This method was added in v1.3.11
        /// This method, when called by an actual Pair contract itself, would return the real fees.
        /// If simply read, it will show basic fees: stableFee, or the volatileFee.
        /// Please use the `getRealFee` method instead for your Analytics / Dapps / Usecases!
        /// If you want to request a flashloan from any Pair, please query `getRealFee` instead.
        /*
        function getFee(bool _stable) public view returns(uint256) {
        	address _c = msg.sender;
        	if(isPair[ _c ]) {
        		uint _fo = feesOverrides[ _c ];
        		if( _fo > 0 ) {
        			return _fo;
        		}
        		else return _stable ? stableFee : volatileFee;	//non-overridden fee is base fee.
        	}
            else return _stable ? stableFee : volatileFee;	//non-pair callers (_c) see base fee.
        }
        */
    
        // Past implementaion of `getFee() for 2° Fees reference
        function getFee(bool _stable) public view returns(uint256) {
            return _stable ? stableFee : volatileFee;
        }
    
        function pairCodeHash() external pure returns (bytes32) {
            return keccak256(type(Pair).creationCode);
        }
    
        function getInitializable() external view returns (address, address, bool) {
            return (_temp0, _temp1, _temp);
        }
    
        function createPair(address tokenA, address tokenB, bool stable) external returns (address pair) {
            require(tokenA != tokenB, "IA"); // Pair: IDENTICAL_ADDRESSES
            (address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
            require(token0 != address(0), "ZA"); // Pair: ZERO_ADDRESS
            require(getPair[token0][token1][stable] == address(0), "PE"); // Pair: PAIR_EXISTS - single check is sufficient
            bytes32 salt = keccak256(abi.encodePacked(token0, token1, stable)); // notice salt includes stable as well, 3 parameters
            (_temp0, _temp1, _temp) = (token0, token1, stable);
            Pair newPair = new Pair{salt:salt}();
            newPair.initialize();
            pair = address(newPair);
            getPair[token0][token1][stable] = pair;
            getPair[token1][token0][stable] = pair; // populate mapping in the reverse direction
            allPairs.push(pair);
            isPair[pair] = true;
            emit PairCreated(token0, token1, stable, pair, allPairs.length);
        }
    
    }

    Please enter a contract address above to load the contract details and source code.

    Context size (optional):