Uniswap v2 remains one of the most widely used decentralized exchanges (DEXs) in the Ethereum ecosystem, enabling seamless token swaps through automated market maker (AMM) mechanics. For developers, traders, and blockchain analysts, understanding how to programmatically retrieve Uniswap v2 pool addresses and real-time token prices is essential for building DeFi tools, conducting arbitrage analysis, or validating on-chain data.
This guide walks you through the technical process of fetching pool addresses using the Uniswap v2 factory contract and calculating accurate token prices using reserve data — all with clean, executable JavaScript code powered by Hardhat and ethers.js.
Core Keywords
- Uniswap v2
- Pool address
- Token price
- getReserves
- Factory contract
- On-chain data
- DeFi development
- Smart contract interaction
Step 1: Retrieve a Uniswap v2 Pool Address
Every liquidity pool in Uniswap v2 is created deterministically via a factory contract, which maps pairs of ERC-20 tokens to their corresponding pair contract address.
To find the pool address for a token pair like FTM/WETH, you need:
- The Uniswap v2 Factory Contract Address
- The token addresses for both assets in the pair
Factory Contract & Token Addresses
const factoryAddress = "0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f"; // Uniswap v2 Factory
const weth = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"; // WETH
const ftm = "0x4e15361fd6b4bb609fa63c81a2be19d873717870"; // FTMThe factory contract provides a getPair(address tokenA, address tokenB) function that returns the pair’s contract address. The order of tokens doesn’t matter — it automatically sorts them.
Code Example: Get FTM/WETH Pool Address
const { ethers } = require("hardhat");
const factoryAddress = "0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f";
const weth = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2";
const ftm = "0x4e15361fd6b4bb609fa63c81a2be19d873717870";
const factoryABI = [
"function getPair(address tokenA, address tokenB) external view returns (address pair)",
"function allPairs(uint) external view returns (address pair)",
"function allPairsLength() external view returns (uint)"
];
async function main() {
const factoryContract = new ethers.Contract(factoryAddress, factoryABI, ethers.provider);
const ftmWethPair = await factoryContract.getPair(ftm, weth);
console.log("FTM/WETH Pool Address: ", ftmWethPair);
}
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});👉 Learn how to interact with DeFi protocols using advanced tools and real-time data.
Output:
FTM/WETH Pool Address: 0x1ffC57cAda109985aD896a69FbCEBD565dB4290eYou can verify this on DexScreener or Etherscan.
Step 2: Fetch Real-Time Token Prices Using Reserves
Once you have the pool address, you can query the current reserve balances of both tokens using the getReserves() method. These reserves represent the liquidity available in the pool and allow you to calculate the exchange rate.
Understanding getReserves()
The getReserves() function returns:
reserve0: Reserve of the first token (alphabetically sorted)reserve1: Reserve of the second tokenblockTimestampLast: Last block timestamp (useful for TWAP calculations)
Calculating Price from Reserves
For the FTM/WETH pair:
If
WETHistoken0andFTMistoken1, then:- Price of FTM in WETH =
reserve0 / reserve1
- Price of FTM in WETH =
- Alternatively, if ordering differs, adjust accordingly.
We use Big.js to handle large integers and avoid floating-point precision loss.
Complete Code Example
const { ethers } = require("hardhat");
const Big = require('big.js');
const factoryAddress = "0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f";
const weth = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2";
const ftm = "0x4e15361fd6b4bb609fa63c81a2be19d873717870";
const factoryABI = [
"function getPair(address tokenA, address tokenB) external view returns (address pair)",
"function allPairs(uint) external view returns (address pair)",
"function allPairsLength() external view returns (uint)"
];
const v2PairABI = [
"function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast)"
];
async function main() {
const factoryContract = new ethers.Contract(factoryAddress, factoryABI, ethers.provider);
const ftmWethPairAddress = await factoryContract.getPair(ftm, weth);
const pairContract = new ethers.Contract(ftmWethPairAddress, v2PairABI, ethers.provider);
const [reserve0, reserve1] = await pairContract.getReserves();
console.log(`FTM/WETH Reserves - Token0: ${reserve0}, Token1: ${reserve1}`);
// Use Big.js for precise division
const price = new Big(reserve1.toString()).div(new Big(reserve0.toString()));
console.log("FTM per WETH:", price.toString());
}
main();Sample Output:
FTM/WETH Reserves - Token0: 3585297124262628787, Token1: 12876524864726044047766
FTM per WETH: 0.00027843670259855536This matches results from platforms like DexScreener — confirming accuracy.
Alternative Method: Using Router's getAmountsIn
Another way to estimate price is via Uniswap’s router contract, which simulates trades including fees and slippage.
Why Use This Method?
While getReserves() gives a theoretical price based on reserves, getAmountsIn() reflects actual trading cost — useful for arbitrage detection or trade execution planning.
Code Example
const routerAddress = "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D"; // Uniswap V2 Router
const routerABI = ["function getAmountsIn(uint amountOut, address[] path) external view returns (uint[] amounts)"];
const routerContract = new ethers.Contract(routerAddress, routerABI, ethers.provider);
const amountOut = ethers.parseUnits('1', 18); // Want 1 FTM
const path = [weth, ftm]; // Path: WETH → FTM
const amountsIn = await routerContract.getAmountsIn(amountOut, path);
console.log("WETH needed for 1 FTM:", ethers.formatUnits(amountsIn[0], 18));Result:
WETH needed for 1 FTM: 0.000278781590931731Note: This value is slightly higher than the reserve-based price due to fee impact and slippage.
👉 Access real-time DeFi analytics and blockchain insights with powerful tools.
Frequently Asked Questions (FAQ)
Q: Can I get all Uniswap v2 pool addresses?
Yes. Use allPairsLength() to get total count and loop through indices with allPairs(uint index) to retrieve each pair address. Be cautious — there are hundreds of thousands of pools.
Q: How do I know which token is reserve0 vs reserve1?
Tokens are sorted by address alphabetically. You can replicate this logic:
[tokenA, tokenB] = [tokenA, tokenB].sort();Then match them with reserve order.
Q: Why does my price calculation show zero?
JavaScript cannot handle large BigInt divisions directly. Always convert to string and use libraries like Big.js, Decimal.js, or ethers.formatUnits() for precision.
Q: Is the price from getReserves() accurate for trading?
It reflects spot price before fees and slippage. For actual trade execution estimates, use router methods like getAmountsIn or getAmountsOut.
Q: What if the pool doesn’t exist?
getPair() returns 0x000... if no pool exists. Always validate the returned address before querying reserves.
Q: Can this work on other chains?
Yes! Just use the correct factory/router addresses for forks like SushiSwap or PancakeSwap on BSC. Logic remains identical.
Final Thoughts
Retrieving Uniswap v2 pool addresses and calculating accurate token prices is foundational knowledge for any DeFi developer or analyst. By leveraging smart contract interactions via ethers.js and handling numerical precision correctly, you can build reliable tools for price monitoring, arbitrage detection, or portfolio tracking.
Whether you're working with FTM/WETH, DAI/USDC, or any ERC-20 pair, the same principles apply across all Uniswap v2-compatible protocols.
👉 Start exploring DeFi data with powerful APIs and trading tools today.