69 lines
2.7 KiB
TypeScript
69 lines
2.7 KiB
TypeScript
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<bigint> => {
|
|
const config = getConfig();
|
|
const cachedPrice = config.PRICE.CACHEDPRICE;
|
|
const timestamp = config.PRICE.TIMESTAMP;
|
|
|
|
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());
|
|
}
|
|
};
|