Getting data from pools

How to determine which token is token0 and which is token1?

The order of the tokens is determined in such a way that:

address(token0) < address(token1)

How to get address of liquidity pool?

To obtain the liquidity pool address, you can use one of the following methods:

1. Use poolByPair mapping in AlgebraFactory

/// @inheritdoc IAlgebraFactory
mapping(address tokenA => mapping(address tokenB => address pool)) public poolByPair;

Documentation: poolByPair

Token addresses must be passed as parameters (in any order). If the pool exists, you will get its address. If such a pool has not yet been created, you will receive address(0).

2. Use computePoolAdress function in AlgebraFactory

/// @inheritdoc IAlgebraFactory
function computePoolAddress(address token0, address token1) public view returns (address pool);

Documentation: computePoolAddress

Token addresses must be passed as parameters ( address(token0) < address(token1) ). You will get address of pool even if it hasn't been created yet.

3. Calculate pool address using create2 mechanism

The previous options require making an external call to the AlgebraFactory contract. A cheaper option in terms of gas would be to calculate the address yourself. To do this, you can use the same logic as in method computePoolAddress:

function computePoolAddress(address token0, address token1) public view returns (address pool) {
  pool = address(uint160(uint256(keccak256(abi.encodePacked(hex'ff', poolDeployer, keccak256(abi.encode(token0, token1)), POOL_INIT_CODE_HASH)))));
}

You need to know POOL_INIT_CODE_HASH constant: you can get it from AlgebraFactory contract . POOL_INIT_CODE_HASH

It is important to note that the calculation uses the address not of the AlgebraFactory, but of the separate pool deployer contract (poolDeployer), you also can get this constant from AlgebraFactory contract poolDeployer.

Also, important to remember that it is important to maintain the order of the tokens: address of token0 must be less than address of token1 (address(token0) < address(token1))

Note: pool address calculation can be different in some blockchains (like zkSync Era).

Price

How to get current price in pool?

Information about the current instant price of the tokens in pool is in the globalState structure:

// AlgebraPool contract

struct GlobalState {
  uint160 price; // The square root of the current price in Q64.96 format
  int24 tick; // The current tick (price(tick) <= current price)
  uint16 lastFee; // The last fee in hundredths of a bip, i.e. 1e-6 (so 100 is 0.01%)
  uint8 pluginConfig; // The current plugin config as a bitmap
  uint16 communityFee; // The community fee represented as a percent of all collected fee in thousandths (1e-3) (so 100 is 10%)
  bool unlocked; // Reentrancy lock flag, true if the contract is unlocked, otherwise - false
}

/// @inheritdoc IAlgebraPoolState
GlobalState public override globalState;

And the safest way to get price and other data is to use special getter function:

/// @dev safe from read-only reentrancy getter function
function safelyGetStateOfAMM() external view override returns (
    uint160 sqrtPrice, 
    int24 tick, 
    uint16 lastFee, 
    uint8 pluginConfig, 
    uint128 activeLiquidity, 
    int24 nextTick, 
    int24 previousTick
)
(uint160 price, , , , , ,) = IAlgebraPool(poolAddress).safelyGetStateOfAMM();

You can get price directly from globalState struct, but beware of read-only reentrancy, if you are doing it on-chain!

Next, it is important to understand what exactly is meant by price in liquidity pools. The pool stores the square root of the price of token0 relative to token1 in format Q64.96. So, in pseudocode, price value in pool can be expressed as:

price_pool = sqrt(reserve_1_virtual / reserve_0_virtual) * 2**96

To get the usual instant price from the price value in the pool, you need to make the following transformations:

price_instant = (price_pool / 2**96)**2

Further, if you need to bring the price to a human-readable form, it is necessary to take into account the difference in token decimals, if any.

Can i use "price" value in pool as real price?

Shortly: no, you should not rely on this raw value for anything other than internal pool calculations. This value in the pool reflects only its internal state at the current moment in time, can change and is subject to manipulation using swaps. In addition, when swapping, the actual execution price will differ from this value due to price impact and fee charged.

To get the real price of the swap, see the paragraph How to get actual execution price for swap?

If you need to get the average price in a pool for a certain period of time, then for this you can use data from a plugin with a TWAP-oracle, if it is connected to the pool.

How to get actual execution price for swap?

To do this, you can use a special peripheral contract called Quoter. For example, here is description of quoteExactInputSingle:

/// @inheritdoc IQuoter
function quoteExactInputSingle(
  address tokenIn,
  address tokenOut,
  uint256 amountIn,
  uint160 limitSqrtPrice
) public override returns (uint256 amountOut, uint16 fee) {
...
}

Quoter

You can do a static call to this method (and it is better not to use it on-chain due to gas costs). As a result, the number of tokens at the output and the real pool fee will be obtained.