Skip to main content

V3 Factory & Pool

V3 Factory

The V3 Factory creates and indexes V3 pools. Unlike V2, the same token pair can have multiple pools with different fee tiers.

Key Functions

getPool

Returns the pool address for a token pair and fee tier.
function getPool(
    address tokenA,
    address tokenB,
    uint24 fee
) external view returns (address pool);
ParameterDescription
tokenA, tokenBToken addresses (order doesn’t matter)
feeFee tier: 100, 500, 3000, or 10000
Returns the zero address if the pool doesn’t exist.

ABI

[
  "function getPool(address tokenA, address tokenB, uint24 fee) view returns (address pool)"
]

V3 Pool

Each V3 Pool contract manages concentrated liquidity positions and swap execution for a specific token pair and fee tier.

Key Functions

slot0

Returns the current pool state.
function slot0() external view returns (
    uint160 sqrtPriceX96,
    int24 tick,
    uint16 observationIndex,
    uint16 observationCardinality,
    uint16 observationCardinalityNext,
    uint8 feeProtocol,
    bool unlocked
);
ReturnDescription
sqrtPriceX96Current price as sqrt(price) * 2^96
tickCurrent tick index
feeProtocolProtocol fee setting
unlockedReentrancy guard state

liquidity

Returns the total active (in-range) liquidity.
function liquidity() external view returns (uint128);

fee / tickSpacing

function fee() external view returns (uint24);
function tickSpacing() external view returns (int24);

token0 / token1

function token0() external view returns (address);
function token1() external view returns (address);

ABI

[
  "function slot0() view returns (uint160 sqrtPriceX96, int24 tick, uint16 observationIndex, uint16 observationCardinality, uint16 observationCardinalityNext, uint8 feeProtocol, bool unlocked)",
  "function liquidity() view returns (uint128)",
  "function fee() view returns (uint24)",
  "function tickSpacing() view returns (int24)",
  "function token0() view returns (address)",
  "function token1() view returns (address)"
]

Example: Read Pool Price

const FACTORY_ABI = [
  "function getPool(address, address, uint24) view returns (address)"
];
const POOL_ABI = [
  "function slot0() view returns (uint160, int24, uint16, uint16, uint16, uint8, bool)",
  "function token0() view returns (address)",
  "function token1() view returns (address)",
  "function fee() view returns (uint24)",
  "function liquidity() view returns (uint128)"
];

const factory = new ethers.Contract(V3_FACTORY, FACTORY_ABI, provider);
const poolAddress = await factory.getPool(tokenA, tokenB, 3000); // 0.3% fee

if (poolAddress === ethers.ZeroAddress) {
  console.log("Pool does not exist for this fee tier");
} else {
  const pool = new ethers.Contract(poolAddress, POOL_ABI, provider);
  const [sqrtPriceX96, tick] = await pool.slot0();

  // Convert sqrtPriceX96 to price
  const price = (Number(sqrtPriceX96) / 2 ** 96) ** 2;
  console.log(`Current price (token1/token0): ${price}`);
  console.log(`Current tick: ${tick}`);
}

Price Conversion

The pool stores price as sqrtPriceX96. To convert:
// sqrtPriceX96 → price (token1 per token0)
const price = (sqrtPriceX96 / 2n ** 96n) ** 2n; // For BigInt

// With decimal adjustment for different token decimals
const adjustedPrice = price * 10n ** BigInt(decimals0 - decimals1);
For precise calculations, use the @uniswap/v3-sdk library or the formulas in Ticks and Ranges.