Price discovery - how to identify most suitable pool?

I’d like to improvement my understanding for the blockchain, it’s use cases and usage day by day. At the moment I’m creating an price oracle for Uniswap v2/v3 and my personal usage. Basically what the moralis getPrice() API is doing. I’m able to fetch the price for a given pair (e.g. DUBBZ/WETH) on Uniswap v2 and v3 (pseudo code below). I also compared the results to the getPrice() API and they’re identical.

One problem left.
Let’s me give you an example.
There are two pools for $PAAL. One on Uniswap v2 and one on Uniswap v3.

The price difference is about 0.002$. How to identify programmatically the most suitable pool for the price discovery? By liquidity? If so how?

@cryptokid @johnversus Could you please tell me how moralis solves this task?

Oracle

async function getAmountsOut(amountIn, path, blockTag = 'latest') {
	let len = path.length;
	let amounts = [amountIn];
	for(let i = 0; i < len - 1; i++) {
		const amountOut = await getAmountOut(amounts[i], path[i], path[i + 1], blockTag);
		if (!amountOut) return undefined;
		amounts[i + 1] = amountOut;
	}

	return amounts[amounts.length - 1];
}

async function getAmountOut(amountIn, srcToken, destToken, blockTag = 'latest') {
	for (const oracle of ORACLES) {
		const amountOut = await oracle.getAmountOut(amountIn, srcToken, destToken, blockTag);
		if (!amountOut) continue;
		return amountOut;
	}

	return undefined;
}

Uniswap v2

async function getAmountOut(amountIn, srcToken, destToken, blockTag = 'latest') {
    const address = await getPool(srcToken, destToken, blockTag);
    if (!address) return undefined;
    const token0 = srcToken < destToken ? srcToken : destToken;
    const [reserve0, reserve1] = await getReserves(address, blockTag);
      if (reserve0 < 1n || reserve1 < 1n) return undefined;
    const [reserveIn, reserveOut] = srcToken == token0 ? [reserve0, reserve1] : [reserve1, reserve0];
    return (amountIn * reserveOut) / reserveIn;
}

Uniswap v3

const Q192 = 2n ** 192n;
async function getAmountOut(amountIn, srcToken, destToken, blockTag = 'latest') {
    const token0 = srcToken < destToken ? srcToken : destToken;
    for (const fee of [500, 3000, 10000]) {
        const address = await getPool(srcToken, destToken, fee, blockTag);
        if (!address) continue;
        const [ sqrtPriceX96 ] = await slot0(address);
        if (token0 == srcToken) {
            return (amountIn * sqrtPriceX96 ** 2n) / Q192;
        }
        else {
            return (amountIn * Q192) / (sqrtPriceX96 ** 2n);
        }
    }

    return undefined;
}

You may not have the same information that we have. One way to do it is by liquidity if you can get the liquidity of that pair or by the number of recent swaps done on each liquidity pair. If the price difference is small then it may not matter for your use case.

I know how to determine the liquidity for Uniswap v2, but not v3. That’s why I’m asking for help :wink:

There should be a way to do it on v3 too. I’m not that familiar with the protocol to tell you the answer directly now. In uniswap v3 multiple pools can be created for the same pair, with different fees.

The thing with multiple pools for one pair is already taken into account in my pseudo code above. If you don’t mind it would be awesome if you could ask one of your developers about my liquidity problem. Thanks in advance

https://bscscan.com/address/0x539e0ebfffd39e54a0f7e5f8fec40ade7933a664#readContract
this contract has a liquidity read only function that you can call, this is what you were looking for?