簡體   English   中英

使用 Web3py 和 Uniswap 對智能合約計算價格:如何處理定點數?

[英]Calculating price using Web3py and Uniswap pair smart contracts: How to deal with fixed point numbers?

我正在嘗試使用 web3.py 和 Uniswap 對合約來計算 Uniswap 中代幣的價格,但我一定在數學上做錯了。 示例:我想計算一個以 USDC 計價的 ETH 的價格。 我首先連接到對合約 USDC/ETH (0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc) 以通過 web3.py 訪問智能合約功能。

如此處所述( https://uniswap.org/docs/v2/smart-contract-integration/building-an-oracle/ )我將price1CumulativeLast()的結果和相關時間戳存儲在兩個不同的時間點(每個 function 通話之間有一分鍾)。 然后我使用公式

(price0CumulativeLATEST — price0CumulativeFIRST) / (timestampOfLATEST — timestampOfFIRST)

(參見: https://medium.com/@epheph/using-uniswap-v2-oracle-with-storage-proofs-3530e699e1d3 )以計算以 token0(USDC)計價的 token1(ETH)的價格。

Uniswap 文檔說 price1CumulativeLast() 返回一個 Q112Q112 定點數,這就是為什么我認為我無法理解這些數字的原因。

我嘗試搜索 Python 函數以輕松將定點 Q112Q112 轉換為浮點數,但沒有找到可行的解決方案,所以我想我一定是在以太坊智能合約或 Uniswap 中使用的數學或單位出現了根本性的錯誤。

def calculate_price():
'''
Call price1CumulativeLast() three times with one minute interval between each call.
'''
results = []
for x in range(3):
    try:
        temp_dict = {}
        start_ts = w3.eth.getBlock(w3.eth.block_number).timestamp
        token1_price_start = contract.functions.price1CumulativeLast().call()
        time.sleep(60*1)
        end_ts = w3.eth.getBlock(w3.eth.block_number).timestamp
        token1_price_end = contract.functions.price1CumulativeLast().call()
        temp_dict['start_ts'] = start_ts
        temp_dict['token1_price_start'] = token1_price_start
        temp_dict['end_ts'] = end_ts
        temp_dict['token1_price_end'] = token1_price_end
        results.append(temp_dict)
    except:
        continue
return results

這給了我:

    results = [{'start_ts': 1623002172,
  'token1_price_start': 183015811459414492033193017518027,
  'end_ts': 1623002242,
  'token1_price_end': 183016664977333417354464783721666},
 {'start_ts': 1623002242,
  'token1_price_start': 183016664977333417354464783721666,
  'end_ts': 1623002250,
  'token1_price_end': 183016664977333417354464783721666},
 {'start_ts': 1623002250,
  'token1_price_start': 183016664977333417354464783721666,
  'end_ts': 1623002355,
  'token1_price_end': 183018525945544514538790080485913}]

我現在在公式中插入兩個時間戳和兩個價格,以在一分鍾的時間間隔內重新計算以 token0 計價的 token1 的價格:

   price = (results[0]['token1_price_end'] - results[0]['token1_price_start']) / (results[0]['end_ts'] - results[0]['start_ts'])
format(price, '.10f')

這將返回以下字符串:

'12193113127504589866663936.0000000000'

在撰寫本文時,這應該是 2800 左右(1 ETH = 2800 USDC),但我不知道如何從這里得到這個數字。 我究竟做錯了什么?

這是一個示例代碼,它使用web3-ethereum-defi 庫以幾種方式計算 Uniswap 對合約價格。

我不認為price1CumulativeLast需要參與。

示例代碼

  • 使用 Uniswap v2 對reserve0reserve1獲取價格條目

  • 最近交易后的價格

  • 時間加權平均價格 (TWAP)

"""Show live BNB/BUSD price from PancakeSwap pool.

- Show the latest price

- Show the TWAP price

Also

- Uses HTTP polling method

- Adjusts for minor chain reorgs / unstable chain tip

To run:

.. code-block:: python

    export BNB_CHAIN_JSON_RPC="https://bsc-dataseed.binance.org/"
    python scripts/live-price.py

"""
import datetime
import os
import time

from web3 import Web3, HTTPProvider
from web3.middleware import geth_poa_middleware

from eth_defi.price_oracle.oracle import PriceOracle, time_weighted_average_price
from eth_defi.uniswap_v2.oracle import update_live_price_feed
from eth_defi.uniswap_v2.pair import fetch_pair_details


def main():
    json_rpc_url = os.environ["BNB_CHAIN_JSON_RPC"]

    web3 = Web3(HTTPProvider(json_rpc_url))
    web3.middleware_onion.clear()
    web3.middleware_onion.inject(geth_poa_middleware, layer=0)

    # https://tradingstrategy.ai/trading-view/binance/pancakeswap-v2/bnb-busd
    pair_contract_address = "0x58F876857a02D6762E0101bb5C46A8c1ED44Dc16"

    reverse_token_order = False

    pair_details = fetch_pair_details(web3, pair_contract_address)

    print(f"Displaying live and TWAP price for {pair_details.token0.symbol} - {pair_details.token1.symbol}")

    price_ticker = f"{pair_details.token0.symbol}/{pair_details.token1.symbol}"

    oracle = PriceOracle(
        time_weighted_average_price,
        max_age=datetime.timedelta(minutes=15),   # Crash if we data gets more stale than 15 minutes
        min_duration=datetime.timedelta(minutes=1),
    )

    # How fast BNB Smart chain ticks
    block_time = 3.0

    initial_fetch_safety_margin = 1.2

    # To back fill the oracle buffer,
    # unitially fetch data for the latest time window blocks plus 20% safety margin
    initial_fetch_block_count = int(oracle.target_time_window / datetime.timedelta(seconds=block_time) * initial_fetch_safety_margin)

    print(f"Starting initial data fetch of {initial_fetch_block_count} blocks")
    update_live_price_feed(
        oracle,
        web3,
        pair_contract_address,
        reverse_token_order=reverse_token_order,
        lookback_block_count=initial_fetch_block_count)

    print(f"Starting live price feed, TWAP time window is set to {oracle.target_time_window}")
    while True:
        stats = update_live_price_feed(
            oracle,
            web3,
            pair_contract_address,
            reverse_token_order=reverse_token_order)

        last_price = oracle.get_newest().price
        twap = oracle.calculate_price()

        oldest = oracle.get_oldest()
        newest = oracle.get_newest()

        print(f"Block {oracle.last_refreshed_block_number:,} at {oracle.last_refreshed_at} current price:{last_price:.4f} {price_ticker} TWAP:{twap:.4f} {price_ticker}")
        print(f"    Oracle data updates: {stats}, trades in TWAP buffer:{len(oracle.buffer)}, oldest:{oldest.timestamp}, newest:{newest.timestamp} ")
        time.sleep(block_time)


if __name__ == "__main__":
    main()

有關更多信息,請參見此處

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM