使用web3js无需调用官方API获取Uniswap、SushiSwap代币价格的方法
Uniswap/SushiSwap V3 链上价格查询(web3.js实现)
一、V3_pool_ABI的获取方式
Uniswap V3、SushiSwap V3的所有流动池合约都遵循统一的标准接口,无需针对单个池单独查询ABI,直接使用官方标准ABI即可,你可以根据需求选择以下两种形式:
- 最小可用ABI片段(仅包含价格查询所需的
slot0、代币地址查询方法,体积更小)
直接将以下JSON赋值给V3_pool_ABI变量即可:[ {"inputs":[],"name":"slot0","outputs":[{"internalType":"uint160","name":"sqrtPriceX96","type":"uint160"},{"internalType":"int24","name":"tick","type":"int24"},{"internalType":"uint16","name":"observationIndex","type":"uint16"},{"internalType":"uint16","name":"observationCardinality","type":"uint16"},{"internalType":"uint16","name":"observationCardinalityNext","type":"uint16"},{"internalType":"uint8","name":"feeProtocol","type":"uint8"},{"internalType":"bool","name":"unlocked","type":"bool"}],"stateMutability":"view","type":"function"}, {"inputs":[],"name":"token0","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}, {"inputs":[],"name":"token1","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"} ] - 全量Pool ABI
如果后续需要查询流动性、tick数据等更多功能,可以直接使用Uniswap官方开源的V3 Pool全量ABI,SushiSwap V3完全兼容该ABI。
二、原有代码的问题修正
你提交的代码存在以下可优化点:
slot0调用多写了一次.call(),正确写法为await pool_1.methods.slot0().call()- 价格计算逻辑错误,
sqrtPriceX96是Q64.96格式的定点数,需要遵循Uniswap V3的官方定价公式转换为可读价格 - 缺少异常捕获逻辑,RPC调用失败时无法排查问题
三、完整可运行代码
const JSBI = require('jsbi'); const Web3 = require('web3'); // V3 流动池标准ABI(最小可用版) const V3_pool_ABI = [ {"inputs":[],"name":"slot0","outputs":[{"internalType":"uint160","name":"sqrtPriceX96","type":"uint160"},{"internalType":"int24","name":"tick","type":"int24"},{"internalType":"uint16","name":"observationIndex","type":"uint16"},{"internalType":"uint16","name":"observationCardinality","type":"uint16"},{"internalType":"uint16","name":"observationCardinalityNext","type":"uint16"},{"internalType":"uint8","name":"feeProtocol","type":"uint8"},{"internalType":"bool","name":"unlocked","type":"bool"}],"stateMutability":"view","type":"function"}, {"inputs":[],"name":"token0","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}, {"inputs":[],"name":"token1","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"} ]; // V3 工厂合约ABI const V3_FACTORY_ABI = [{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint24","name":"fee","type":"uint24"},{"indexed":true,"internalType":"int24","name":"tickSpacing","type":"int24"}],"name":"FeeAmountEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token0","type":"address"},{"indexed":true,"internalType":"address","name":"token1","type":"address"},{"indexed":true,"internalType":"uint24","name":"fee","type":"uint24"},{"indexed":false,"internalType":"int24","name":"tickSpacing","type":"int24"},{"indexed":false,"internalType":"address","name":"pool","type":"address"}],"name":"PoolCreated","type":"event"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"}],"name":"createPool","outputs":[{"internalType":"address","name":"pool","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"int24","name":"tickSpacing","type":"int24"}],"name":"enableFeeAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint24","name":"","type":"uint24"}],"name":"feeAmountTickSpacing","outputs":[{"internalType":"int24","name":"","type":"int24"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint24","name":"","type":"uint24"}],"name":"getPool","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"parameters","outputs":[{"internalType":"address","name":"factory","type":"address"},{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"int24","name":"tickSpacing","type":"int24"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"nonpayable","type":"function"}] // 以太坊主网V3工厂地址配置 const FACTORY_CONFIG = { uniswapV3: '0x1F98431c8aD98523631AE4a59f267346ea31F984', sushiswapV3: '0xbACEB8eC6b9355Dfc0269a83b980cb3992bbCf6A' } (async () => { // 初始化RPC连接,建议替换为你自己的Infura/Alchemy节点地址 const web3 = new Web3(new Web3.providers.HttpProvider('https://mainnet.infura.io/v3/d5658a9beace4cd98d2c1216cf66b56a')); try { // 示例:查询Uniswap V3 DAI/WETH 0.3%费率池价格 // 要查询SushiSwap V3价格,将下方FACTORY_CONFIG.uniswapV3替换为FACTORY_CONFIG.sushiswapV3即可 const factoryContract = new web3.eth.Contract(V3_FACTORY_ABI, FACTORY_CONFIG.uniswapV3); // 参数依次为:代币A地址、代币B地址、费率(3000=0.3%,常见值还有500=0.05%、10000=1%) const poolAddress = await factoryContract.methods.getPool( '0x6b175474e89094c44da98b954eedeac495271d0f', // DAI地址 '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', // WETH地址 3000 ).call(); console.log('流动池地址:', poolAddress); const poolContract = new web3.eth.Contract(V3_pool_ABI, poolAddress); const slot0Data = await poolContract.methods.slot0().call(); const sqrtPriceX96 = JSBI.BigInt(slot0Data.sqrtPriceX96); // 价格转换公式,适配精度相同的代币(DAI和WETH精度均为18) const Q192 = JSBI.exponentiate(JSBI.BigInt(2), JSBI.BigInt(192)); const wethToDaiPrice = Number(JSBI.divide(JSBI.multiply(sqrtPriceX96, sqrtPriceX96), Q192)); console.log('1 WETH = ', wethToDaiPrice.toFixed(2), ' DAI'); } catch (error) { console.error('查询失败:', error.message); } })();
四、使用说明
- 运行前先安装依赖:
npm install jsbi web3 - 如果查询的两个代币精度不同,将价格转换逻辑中对应的精度值替换即可,比如USDC精度为6,就将对应系数改为1e6
- 若要查询其他交易对,替换
getPool方法中的代币地址和对应费率即可
内容的提问来源于stack exchange,提问作者AtiqGauri
相关产品推荐
相关产品推荐

