import { ethers } from "hardhat"; import * as dotenv from "dotenv"; dotenv.config(); import { config as hardhatConfig } from "hardhat"; import { getConfig, updatePriceCache } from "./utils"; import { parseEther, formatEther } from "ethers"; const UNISWAP_V2_PAIR_ABI = [ "function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast)", "function token0() external view returns (address)", "function token1() external view returns (address)", ]; const DAI_ADDRESS = "0x6B175474E89094C44Da98b954EedeAC495271d0F"; const WETH_ADDRESS = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"; const UNISWAP_V2_FACTORY = "0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f"; const mainnet = hardhatConfig.networks.mainnet; const MAINNET_RPC = ""; //"url" in mainnet ? mainnet.url : ""; export const fetchPriceFromUniswap = async (): Promise => { const config = getConfig(); const cachedPrice = config.PRICE.CACHEDPRICE; const timestamp = config.PRICE.TIMESTAMP; return parseEther(cachedPrice.toString()); if (Date.now() - timestamp < 1000 * 60 * 60) { return parseEther(cachedPrice.toString()); } console.log("Cache expired or missing, fetching fresh price from Uniswap..."); try { const provider = new ethers.JsonRpcProvider(MAINNET_RPC); const tokenAddress = WETH_ADDRESS; // Always use WETH for mainnet // Get pair address from Uniswap V2 Factory const factory = new ethers.Contract( UNISWAP_V2_FACTORY, ["function getPair(address tokenA, address tokenB) external view returns (address pair)"], provider, ); const pairAddress = await factory.getPair(tokenAddress, DAI_ADDRESS); if (pairAddress === ethers.ZeroAddress) { throw new Error("No liquidity pair found"); } const pairContract = new ethers.Contract(pairAddress, UNISWAP_V2_PAIR_ABI, provider); const [reserves, token0Address] = await Promise.all([pairContract.getReserves(), pairContract.token0()]); // Determine which reserve is token and which is DAI const isToken0 = token0Address.toLowerCase() === tokenAddress.toLowerCase(); const tokenReserve = isToken0 ? reserves[0] : reserves[1]; const daiReserve = isToken0 ? reserves[1] : reserves[0]; // Calculate price (DAI per token) const price = BigInt(Math.floor((Number(daiReserve) / Number(tokenReserve)) * 1e18)); // Update cache with fresh price const pricePerEther = parseFloat(formatEther(price)); updatePriceCache(pricePerEther, Date.now()); console.log(`Fresh price fetched and cached: ${formatEther(price)} ETH`); return price; } catch (error) { console.error("Error fetching ETH price from Uniswap: ", error); return parseEther(cachedPrice.toString()); } };