💬

JavaScriptでUniswap v3から価格を取得する。

2022/03/09に公開

前提

JavaScript(Node.js)でUniswap v3から価格を取得しようとしたのだが、色々めんどくさかったので書きます。

  • トークンのコントラクトアドレスのペアから価格を取得する。
  • Infuraやalchemyのノードプロバイダーを利用する。

準備

各種パッケージをインストール
npm i --save ethers
npm i --save @uniswap/v3-sdk
npm i --save @uniswap/sdk-core

公式ページ

公式はこちら。
https://docs.uniswap.org/sdk/guides/fetching-prices
プールアドレスを調べなきゃいけなかったり、最後のオブジェクトからどうやって出力するのかだったり、わかりにくいところが多いので、以下ではトークンアドレスのペアから最後の出力まで一気通貫でやりました。

コード

const ethers = require("ethers");
const Pool = require("@uniswap/v3-sdk").Pool;
const Token = require("@uniswap/sdk-core").Token;
const IUniswapV3PoolABI = require("@uniswap/v3-core/artifacts/contracts/interfaces/IUniswapV3Pool.sol/IUniswapV3Pool.json").abi;
const UniswapV3Factory_ABI = require("@uniswap/v3-core/artifacts/contracts/UniswapV3Factory.sol/UniswapV3Factory.json").abi;
//必要なname,decimals,symbolのみ。
const ERC20ABI = [
  {
      "constant": true,
      "inputs": [],
      "name": "name",
      "outputs": [
          {
              "name": "",
              "type": "string"
          }
      ],
      "payable": false,
      "stateMutability": "view",
      "type": "function"
  },
  {
      "constant": true,
      "inputs": [],
      "name": "decimals",
      "outputs": [
          {
              "name": "",
              "type": "uint8"
          }
      ],
      "payable": false,
      "stateMutability": "view",
      "type": "function"
  },
  {
      "constant": true,
      "inputs": [],
      "name": "symbol",
      "outputs": [
          {
              "name": "",
              "type": "string"
          }
      ],
      "payable": false,
      "stateMutability": "view",
      "type": "function"
  },
];



async function uniswapPrice(tokenAaddress, tokenBaddress, provider){
  //ネットワーク取得
  const network = await provider.getNetwork();

  //Uniswapコントラクト実装
  const uniswapContract = new ethers.Contract(
    "0x1F98431c8aD98523631AE4a59f267346ea31F984", //全ネットワークで共通 https://docs.uniswap.org/protocol/reference/deployments
    UniswapV3Factory_ABI,
    provider,
  );

  //トークンコントラクト実装
  const tokenAContract = new ethers.Contract(
    tokenAaddress,
    ERC20ABI,
    provider,
  );
  const tokenBContract = new ethers.Contract(
    tokenBaddress,
    ERC20ABI,
    provider,
  );

  //トークン属性取得
  const [tokenAname, tokenAsymbol, tokenAdecimals,tokenBname, tokenBsymbol, tokenBdecimals] =
    await Promise.all([
      tokenAContract.name(),
      tokenAContract.symbol(),
      tokenAContract.decimals(),
      tokenBContract.name(),
      tokenBContract.symbol(),
      tokenBContract.decimals(),
    ]);

  //プールアドレス取得
  const poolAddress = await uniswapContract.getPool(
    tokenAaddress,
    tokenBaddress,
    3000
    );

  //プールが存在しない時は終了。
  if(poolAddress == '0x0000000000000000000000000000000000000000'){
    console.log('No Pool');
    return ;
  }

  //プールコントラクト実装
  const poolContract = new ethers.Contract(
    poolAddress,
    IUniswapV3PoolABI,
    provider
  );

  //プール属性取得
  const [token0address,token1address, fee, liquidity, slot] =
    await Promise.all([
      poolContract.token0(),
      poolContract.token1(),
      poolContract.fee(),
      poolContract.liquidity(),
      poolContract.slot0(),
    ]);


  //トークン実装
  const TokenA = new Token(network.chainId, tokenAaddress, tokenAdecimals, tokenAsymbol, tokenAname);
  const TokenB = new Token(network.chainId, tokenBaddress, tokenBdecimals, tokenBsymbol, tokenBname);

  //プール実装
  const pool = new Pool(
    TokenA,
    TokenB,
    fee,
    slot[0].toString(),
    liquidity.toString(),
    slot[1]
  );

  //出力
  var tokenAPrice;
  var tokenBPrice;
  if(tokenAaddress == token0address){ //プールでのトークン0、トークン1は入力値とは逆になっていることもある。
    tokenAPrice = pool.token0Price;
    tokenBPrice = pool.token1Price;
  }else{
    tokenAPrice = pool.token1Price;
    tokenBPrice = pool.token0Price;
  }
  console.log(`1${tokenAsymbol} = ${Number(tokenAPrice.toSignificant(10))}${tokenBsymbol}`);
  console.log(`1${tokenBsymbol} = ${Number(tokenBPrice.toSignificant(10))}${tokenAsymbol}`);

}

async function main() {

  const usdcAddress = "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174";
  const wethAddress = "0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619";

  const polygon_provider = new ethers.providers.JsonRpcProvider(
    "https://polygon-mainnet.infura.io/v3/< your key >"
  );

  await uniswapPrice(usdcAddress,wethAddress,polygon_provider);

}
main();

出力

で、 main関数の< your key >をInfuraで取得したkeyに書き換えて、node <file名>.jsで実行すると

ちなみに、トークンアドレスのペアでプールが存在しないとエラー終了します。
存在するペアの掛け算で求めましょう。

Discussion