• Web3.py是与Ethereum交互的Python库。功能包括连接到以太坊网络节点、检索数据和向以太坊网络广播数据。
pip install web3

目前以太坊全节点数据量高达数TB,自建本地全节点不太现实,因此一般通过Infura等的网关来实现数据查询。在 Infura 新建一个项目获取API KEY

from web3 import Web3
chainApi = Web3(Web3.HTTPProvider('https://mainnet.infura.io/v3/6efdb....(替换为你的API KEY)'))
# 获取最新区块数据
block = chainApi.eth.getBlock("latest")
print(block)
# 获取某地址的余额
balance = chainApi.eth.getBalance("0x7A6381...(替换为你要查询的地址)")
print(balance)

与ERC-20合约交互

需求:识别当前用户地址持有的 token 资产的美元价格,统计资产总净值


实现思路:1. 首先要扫描钱包地址,查看持有哪些代币(需要与各ERC20合约交互)。2. 计算代币的美元价值来计算总净值。

第一步

符合ERC-20合约规范的都带有以下函数:

function name() public view returns (string)
function symbol() public view returns (string)
function decimals() public view returns (uint8)
function totalSupply() public view returns (uint256)
function balanceOf(address _owner) public view returns (uint256 balance)
function transfer(address _to, uint256 _value) public returns (bool success)
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success)
function approve(address _spender, uint256 _value) public returns (bool success)
function allowance(address _owner, address _spender) public view returns (uint256 remaining)
  • ​​balanceOf​ ​是用于查询钱包地址持有多少代币的函数。

与合约交互需要通过 ABI:application binary interface。ABI用来定义数据在EVM中应该如何编码/解码。

这里以Synthetix(SNX)合约为例,示例代码如下:

import json
ABI = json.loads('[{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}]')

wallet_address = '0x7A638...(换成你的地址)'
wallet_address = Web3.toChecksumAddress(wallet_address)

token_contract_address = '0xc011a73ee8576fb46f5e1c5751ca3b9fe0af2a6f' # SNX合约地址
token_contract_address = Web3.toChecksumAddress(token_contract_address)

# define contract
contract = chainApi.eth.contract(token_contract_address, abi=ABI)

# call contract and get data from balanceOf for argument wallet_address
raw_balance = contract.functions.balanceOf(wallet_address).call()

# convert the value from Wei to Ether
synthetix_value = Web3.fromWei(raw_balance, 'ether')

print(synthetix_value)
  • ​​toChecksumAddress()​​来确保我们的地址是校验格式的
  • fromWei()​​将我们的Wei价格转换为 ether 1ETH是 1 0 18 10^{18} 1018 Wei

要遍历所有 token 资产可以通过建立一个 ERC-20 合约地址的主列表,并通过迭代来找到特定钱包所持有的代币。

第二步
使用 The Graph 获取行情数据(美元价格)

from gql import gql, Client
from gql.transport.requests import RequestsHTTPTransport

sample_transport = RequestsHTTPTransport(
   url='https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v2',
   verify=True,
   retries=5,
)
client = Client(transport=sample_transport)

# Get the value of SNX/ETH
query = gql('''
    query {
        pair(id: "0x43ae24960e5534731fc831386c07755a2dc33d47"){
            reserve0
            reserve1
        }
    }
''')
response = client.execute(query)
snx_eth_pair = response['pair']
eth_value = float(snx_eth_pair['reserve1']) / float(snx_eth_pair['reserve0'])

# Get the value of ETH/DAI
query = gql('''
query {
    pair(id: "0xa478c2975ab1ea89e8196811f51a7b7ade33eb11"){
        reserve0
        reserve1
    }
}
''')
response = client.execute(query)
eth_dai_pair = response['pair']
dai_value = float(eth_dai_pair['reserve0']) / float(eth_dai_pair['reserve1'])

snx_dai_value = eth_value * dai_value
print(snx_dai_value)

通过 DEX 的数据来计算 SNX 与锚定美元的稳定币的汇率,这里以 ETH 为中间币种做了两次计算(DAI 稳定币锚定美元)。
对 The Graph 进行查询,以获得 SNX 的 DAI 价值。我们首先得到每一个 SNX 的 ETH 价值,然后乘以与一个 ETH 等值的 DAI 数量,得到一个 SNX 的 DAI 价值。将最终的 DAI 值乘以我们钱包持有的 SNX 数量,找到头寸的总美元价值。

Reference

[1]用Web3.py、Infura和Graph查询以太坊数据

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐