Construct a gas strategy with fallback chain of oracles

pull/2154/head
David Núñez 2020-07-23 18:31:32 +02:00
parent d6c986d9bb
commit b29f4fb379
1 changed files with 25 additions and 2 deletions

View File

@ -19,7 +19,8 @@ from typing import Optional
import requests
from web3 import Web3
from web3.types import Wei
from web3.gas_strategies.rpc import rpc_gas_price_strategy
from web3.types import Wei, TxParams
class Oracle(ABC):
@ -27,6 +28,7 @@ class Oracle(ABC):
class OracleError(RuntimeError):
"""Base class for Oracle-related exceptions"""
name = NotImplemented
api_url = NotImplemented # TODO: Deal with API keys
def _probe_oracle(self):
@ -61,16 +63,20 @@ class EthereumGasPriceOracle(Oracle):
@classmethod
def construct_gas_strategy(cls):
def oracle_based_gas_price_strategy(web3, transaction_params=None) -> Wei:
def oracle_based_gas_price_strategy(web3: Web3, transaction_params: TxParams = None) -> Wei:
oracle = cls()
gas_price = oracle.get_gas_price()
return gas_price
return oracle_based_gas_price_strategy
def __repr__(self):
return f"{self.name} ({self.api_url})"
class EtherchainGasPriceOracle(EthereumGasPriceOracle):
"""Gas price oracle from Etherchain"""
name = "Etherchain oracle"
api_url = "https://www.etherchain.org/api/gasPriceOracle"
_speed_names = ('safeLow', 'standard', 'fast', 'fastest')
_default_speed = 'fast'
@ -83,6 +89,7 @@ class EtherchainGasPriceOracle(EthereumGasPriceOracle):
class UpvestGasPriceOracle(EthereumGasPriceOracle):
"""Gas price oracle from Upvest"""
name = "Upvest oracle"
api_url = "https://fees.upvest.co/estimate_eth_fees"
_speed_names = ('slow', 'medium', 'fast', 'fastest')
_default_speed = 'fastest'
@ -92,6 +99,22 @@ class UpvestGasPriceOracle(EthereumGasPriceOracle):
self.gas_prices = {k: int(Web3.toWei(v, 'gwei')) for k, v in self._raw_data['estimates'].items()}
def oracle_fallback_gas_price_strategy(web3: Web3, transaction_params: TxParams = None) -> Wei:
oracles = (EtherchainGasPriceOracle, UpvestGasPriceOracle)
for gas_price_oracle_class in oracles:
try:
gas_strategy = gas_price_oracle_class.construct_gas_strategy()
gas_price = gas_strategy(web3, transaction_params)
except EtherchainGasPriceOracle.OracleError:
continue
else:
return gas_price
else:
# Worst-case scenario, we get the price from the ETH node itself
return rpc_gas_price_strategy(web3, transaction_params)
# TODO: We can implement here other oracles, like the ETH/USD (e.g., https://api.coinmarketcap.com/v1/ticker/ethereum/)
# suggested in a comment in nucypher.blockchain.eth.interfaces.BlockchainInterface#sign_and_broadcast_transaction