背景
Uniswap での流動性ペアの各トークン量をスクリプトで取得したい.
税金の損益計算で必要だったり, 価格の歪みが生じていて裁定の機会がないかチェックしたい, など.
etherscan で調べるのはできるが, API 叩いて取得などは PRO 版でないと無理っぽい.
Python web3 で取得してみます.
ブロックチェーンノードを用意する
- geth を自分で立てる
- infra などのサービスを使う
今回は infra 使います. アカウント登録して project id を取得しておきます.
chainlink が public なノード建ててくれていました. こちらも使えます.
ただ, 最新ブロックのみ取得できました.
過去のデータにアクセスするには archive node を建てるか(geth --syncmode full --gcmode archive
), archive node へのアクセスを提供しているサービス使う必要あります(後述)
コード
WETH/USDT の残高を調べます.
import json
from web3 import Web3,HTTPProvider
web3 = Web3(HTTPProvider('https://mainnet.infura.io/v3/<project_id>'))
blockNumber=web3.eth.blockNumber
print(blockNumber)
addr_weth_usdt = '0x0d4a11d5EEaaC28EC3F61d100daF4d40471f1852' # Uniswap WETH/USDT pair
abi_weth_usdt = json.loads(open('abi.json').read())
contract = web3.eth.contract(address=addr_weth_usdt, abi=abi_weth_usdt)
print("decimals", contract.functions.decimals().call())
print("totalSupply", contract.functions.totalSupply().call())
print("token0 addr", contract.functions.token0().call())
print("token1 addr", contract.functions.token1().call())
print("reserves(token0, token1, blocktime): ", contract.functions.getReserves().call())
abi JSON 情報はとりあえず etherscan から取得しました.
python web3 ですと ABI で定義された関数を取り込むと, contract.functions.****().call()
でメソッドとして呼び出せます. メソッドパラメータは etherscan 上でのコントラクトソースコードを参照ください.
12068697
decimals 18
totalSupply 2237106473773835710
token0 addr 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
token1 addr 0xdAC17F958D2ee523a2206206994597C13D831ec7
reserves(token0, token1, blocktime): [77593590686712646780933, 139661541958582, 1616150417]
Voila!
token0 が WETH, token1 が USDT ですね.
etherscan での残高と見比べて同じであるのが確認できました.
特定のブロックのときの残高を調べる
print("reserves(token0, token1, blocktime): ", contract.functions.getReserves().call(block_identifier=12068708))
のようにしてブロック番号やブロックハッシュ指定でいけるようですが... 少し古いブロック番号を指定するとエラーになります(403 forbidden). linkpool のも timeout error.
infra だと履歴にアクセスするには data archive アドオン課金($250/month)しないとダメでした.
呼び出し数すくなければ quicknode がよさそうです.
TODO
- geth だと archive node には 7TB くらい必要(2021/03 時点)なので, 1.5 TB くらいで収まるっぽい TurboGeth で archive node を建てる.
- GraphQL で取得できないか試す. bitQuery で試せます: https://graphql.bitquery.io/ide