💬
JavaScriptでUniswap v3から価格を取得する。
前提
JavaScript(Node.js)でUniswap v3から価格を取得しようとしたのだが、色々めんどくさかったので書きます。
- トークンのコントラクトアドレスのペアから価格を取得する。
- Infuraやalchemyのノードプロバイダーを利用する。
準備
各種パッケージをインストール
npm i --save ethers
npm i --save @uniswap/v3-sdk
npm i --save @uniswap/sdk-core
公式ページ
公式はこちら。
プールアドレスを調べなきゃいけなかったり、最後のオブジェクトからどうやって出力するのかだったり、わかりにくいところが多いので、以下ではトークンアドレスのペアから最後の出力まで一気通貫でやりました。コード
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