获取Uniswap v2交易对池子的地址以及价格的方法
获取池子地址
以FTM/WETH为例,根据以太坊主网上Uniswap v2工厂合约、WETH、FTM的三个合约的地址,使用工厂合约的getPair函数,即可查到池子地址。
代码如下:
const { ethers } = require("hardhat");
const factoryAddress = "0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f"; //Uniswap工厂合约地址
const weth = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2";
const ftm = "0x4e15361fd6b4bb609fa63c81a2be19d873717870";
//interface IUniswapV2Factory , 在ABI中列出用到的方法
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 ftm_weth = await factoryContract.getPair(ftm, weth);
console.log("FTM/WETH Uniswap V2池子地址: %s", ftm_weth);
}
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
FTM/WETH Uniswap V2池子地址: 0x1ffC57cAda109985aD896a69FbCEBD565dB4290e
https://dexscreener.com/ethereum/0x1ffc57cada109985ad896a69fbcebd565db4290e
获取交易对价格
还是以FTM/WETH为例,获取到pair address以后,就可以用PairContract的getReserves()函数获取两个Token的储备量,进而计算出当前价格。
完善上面的代码后:
const { ethers } = require("hardhat");
const Big = require('big.js');
const factoryAddress = "0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f"; //Uniswap工厂合约地址
const weth = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2";
const ftm = "0x4e15361fd6b4bb609fa63c81a2be19d873717870";
//interface IUniswapV2Factory , 在ABI中列出用到的方法
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 allPairsLength = await factoryContract.allPairsLength();
console.log("当前Uniswap V2共有%s个池子", allPairsLength);
// 遍历获取前10个池子的地址
let pairs = [];
for (let i = 0; i < 10; i++) {
let pairAddress = await factoryContract.allPairs(i);
pairs.push(pairAddress);
console.log(pairAddress);
}
console.log(pairs.length);
const ftm_weth_address = await factoryContract.getPair(ftm, weth);
console.log("FTM/WETH Uniswap V2池子地址: %s", ftm_weth_address);
const ftmWethPairContract = new ethers.Contract(ftm_weth_address, v2PairABI, ethers.provider);
const [reserve0, reserve1, timestamp] = await ftmWethPairContract.getReserves();
console.log("FTM/WETH:%s, FTM储备%s, WETH储备%s, 时间戳%s", ftm_weth_address, reserve0, reserve1, timestamp);
console.log("FTM/WETH价格: %s", reserve1/reserve0);
console.log("FTM/WETH价格: %s", new Big(reserve1).div(new Big(reserve0)).toString());
}
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
运行结果:
> npx hardhat run .\ignition\modules\uniswapv2.js --network hardhat
当前Uniswap V2共有376616n个池子
0xB4e16d0168e52d35CaCD2c6185b44281Ec28C9Dc
0x3139Ffc91B99aa94DA8A2dc13f1fC36F9BDc98eE
0x12EDE161c702D1494612d19f05992f43aa6A26FB
0xA478c2975Ab1Ea89e8196811F51A7B7Ade33eB11
0x07F068ca326a469Fc1d87d85d448990C8cBa7dF9
0xAE461cA67B15dc8dc81CE7615e0320dA1A9aB8D5
0xCe407CD7b95B39d3B4d53065E711e713dd5C5999
0x33C2d48Bc95FB7D0199C5C693e7a9F527145a9Af
0xB6909B960DbbE7392D405429eB2b3649752b4838
0x30EB5E15476E6a80F4F3cd8479749b4881DAB1b8
10
FTM/WETH Uniswap V2池子地址: 0x1ffC57cAda109985aD896a69FbCEBD565dB4290e
FTM/WETH:0x1ffC57cAda109985aD896a69FbCEBD565dB4290e, FTM储备12876524864726044047766n, WETH储备3585297124262628787n, 时间戳1728374375n
FTM/WETH价格: 0n
FTM/WETH价格: 0.00027843670259855536
这里用到了Big.js这个库来解决精度丢失问题,最后得到FTM兑WETH价格是0.00027843670259855536
,这与dexscreener.com查询的结果是一致的。
获取交易对价格(方式2)
const routerContract = new ethers.Contract(routerAddress, routerABI, ethers.provider);
const amountOut = ethers.parseUnits('1', 18);
const price11 = await routerContract.getAmountsIn(amountOut, [wethAddress, ftmAddress]);
console.log("FTM/WETH链上价格(方式2): %s", ethers.formatUnits(price11[0], 18));
运行结果
FTM/WETH链上价格: 0.00027792368608291437
FTM/WETH链上价格(方式2): 0.000278781590931731
说明:
- router.getAmountsIn(amountOut,path)这种方式是考虑了手续费和滑点的,所以得出的eth->ftm的FTM/WETH价格更贵。
- 注意里边的单位问题,FTM和ETH的最小单位都是小数点后18位,所以1 FTM = ethers.parseUnits('1', 18)