获取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

说明:

  1. router.getAmountsIn(amountOut,path)这种方式是考虑了手续费和滑点的,所以得出的eth->ftm的FTM/WETH价格更贵。
  2. 注意里边的单位问题,FTM和ETH的最小单位都是小数点后18位,所以1 FTM = ethers.parseUnits('1', 18)

posted on 2024-10-08 11:15  肥兔子爱豆畜子  阅读(63)  评论(0编辑  收藏  举报

导航