如何用Uniswap SDK获取代币对历史汇率及当前汇率?
Uniswap SDK 相关问题解答
一、通过SDK获取当前兑换汇率(x和y的当前储备量)
Uniswap SDK(V2/V3逻辑类似)可直接从链上拉取资金池的实时储备数据,进而计算当前汇率。
V2版本示例代码
import { ChainId, Token, Pair, Fetcher } from '@uniswap/sdk'; // 定义目标代币与链ID const tokenX = new Token(ChainId.MAINNET, '0x...', 18); // 替换为X代币地址 const tokenY = new Token(ChainId.MAINNET, '0x...', 18); // 替换为Y代币地址 // 获取资金池实例 const pair = await Fetcher.fetchPairData(tokenX, tokenY); // 提取当前储备量 const reserveX = pair.reserve0; const reserveY = pair.reserve1; // 计算1枚X代币可兑换的Y代币数量 const rateXtoY = reserveY.divide(reserveX).toSignificant(6); console.log(`当前1 X = ${rateXtoY} Y`);
说明:Fetcher会自动从链上获取最新储备数据,reserve0/reserve1对应排序后的两种代币储备,可根据代币地址匹配x/y对应关系。
V3版本示例代码
import { ChainId, Token, Pool, FeeAmount } from '@uniswap/v3-sdk'; import { ethers } from 'ethers'; // 初始化以太坊Provider const provider = new ethers.providers.JsonRpcProvider('https://mainnet.infura.io/v3/your-api-key'); // 定义代币与手续费层级 const tokenX = new Token(ChainId.MAINNET, '0x...', 18); const tokenY = new Token(ChainId.MAINNET, '0x...', 18); const feeAmount = FeeAmount.MEDIUM; // 0.3%手续费层级 // 获取资金池合约并调用slot0接口 const poolAddress = Pool.getAddress(tokenX, tokenY, feeAmount); const poolContract = new ethers.Contract( poolAddress, ['function slot0() view returns (uint160 sqrtPriceX96, int24 tick, uint16 observationIndex, uint16 observationCardinality, uint16 observationCardinalityNext, uint8 feeProtocol, bool unlocked)'], provider ); const slot0 = await poolContract.slot0(); // 从sqrtPriceX96转换为实际汇率(考虑代币精度) const sqrtPriceX96 = slot0.sqrtPriceX96; const rawPriceXtoY = (sqrtPriceX96 ** 2) / (2 ** 192); const formattedPrice = ethers.utils.formatUnits(rawPriceXtoY.toString(), tokenY.decimals - tokenX.decimals); console.log(`当前1 X = ${formattedPrice} Y`);
说明:V3用sqrtPriceX96存储价格,需通过公式转换为可读汇率,同时要兼容两种代币的精度差异。
二、获取xy=k曲线的历史数据(SDK原生方案限制)
Uniswap SDK本身没有内置历史数据查询接口,核心聚焦实时链上交互。若要基于SDK实现历史数据获取,有两种可行思路:
思路1:结合历史区块查询
利用以太坊Provider的历史区块调用能力,指定目标区块号,调用资金池合约的getReserves(V2)或slot0(V3)接口,手动提取对应区块的储备/价格数据,再计算历史k值。
示例(V2 + ethers):const targetBlock = 17000000; // 目标历史区块号 const historicalReserves = await pair.contract.getReserves({ blockTag: targetBlock }); const historicalReserveX = historicalReserves[0]; const historicalReserveY = historicalReserves[1]; const historicalK = historicalReserveX.mul(historicalReserveY); console.log(`区块${targetBlock}的k值:${historicalK.toString()}`);注意:该方式适合少量历史区块查询,批量查询易触发节点限制,效率较低。
思路2:基于SDK兼容的社区工具
部分Uniswap社区工具(如@uniswap/v3-staker衍生工具)会封装历史数据查询逻辑,但本质仍是调用链上历史区块接口,未脱离链上查询范畴。
若需批量获取历史数据,GraphQL(如Uniswap Subgraph)仍是更高效的方案;若坚持纯SDK路线,只能通过上述历史区块调用方式实现。
内容的提问来源于stack exchange,提问作者efwefwefwefwefw wefwefwefwef
相关产品推荐
相关产品推荐

