From 073c99f59e92f5dcb139f0aa207309d9653f5ad3 Mon Sep 17 00:00:00 2001 From: troy Date: Fri, 2 Aug 2024 13:05:42 -0600 Subject: [PATCH] Bug: Disabled perps markets (#59) * add disabled markets * update docs and linting --- src/synthetix/perps/constants.py | 3 +++ src/synthetix/perps/perps.py | 28 ++++++++++++++++++---------- src/synthetix/pyth/pyth.py | 9 +++++++++ src/synthetix/synthetix.py | 13 +++++++++---- 4 files changed, 39 insertions(+), 14 deletions(-) create mode 100644 src/synthetix/perps/constants.py diff --git a/src/synthetix/perps/constants.py b/src/synthetix/perps/constants.py new file mode 100644 index 0000000..f5bf340 --- /dev/null +++ b/src/synthetix/perps/constants.py @@ -0,0 +1,3 @@ +DISABLED_MARKETS = { + 8453: [6300] +} \ No newline at end of file diff --git a/src/synthetix/perps/perps.py b/src/synthetix/perps/perps.py index ed8e54f..1a46689 100644 --- a/src/synthetix/perps/perps.py +++ b/src/synthetix/perps/perps.py @@ -9,6 +9,7 @@ write_erc7412, make_fulfillment_request, ) +from .constants import DISABLED_MARKETS class Perps: @@ -38,18 +39,23 @@ class Perps: - PythERC7412Wrapper :param Synthetix snx: An instance of the Synthetix class. - :param Pyth pyth: An instance of the Pyth class. :param int | None default_account_id: The default ``account_id`` to use for transactions. + :param list | None : A list of market ids to disable. :return: An instance of the Perps class. :rtype: Perps """ - def __init__(self, snx, default_account_id: int = None): + def __init__(self, snx, default_account_id: int = None, disabled_markets=None): self.snx = snx self.logger = snx.logger self.erc7412_enabled = True + if disabled_markets is None and snx.network_id in DISABLED_MARKETS: + self.disabled_markets = DISABLED_MARKETS[snx.network_id] + else: + self.disabled_markets = [] + # check if perps is deployed on this network if "perpsFactory" in snx.contracts: self.market_proxy = snx.contracts["perpsFactory"]["PerpsMarketProxy"][ @@ -208,6 +214,13 @@ def get_markets(self): """ market_ids = self.market_proxy.functions.getMarkets().call() + # filter disabled markets + market_ids = [ + market_id + for market_id in market_ids + if market_id not in self.disabled_markets + ] + # fetch and store the metadata market_metadata = multicall_erc7412( self.snx, self.market_proxy, "metadata", market_ids @@ -581,9 +594,7 @@ def get_margin_info(self, account_id: int = None): } else: - collateral_amount_dict = { - 0: wei_to_ether(total_collateral_value) - } + collateral_amount_dict = {0: wei_to_ether(total_collateral_value)} debt = 0 return { @@ -952,7 +963,7 @@ def pay_debt( Pay the debt of a perps account. If no amount is provided, the full debt of the account is repaid. Make sure to approve the proxy to transfer sUSD before calling this function. - + :param int | None amount: The amount of debt to repay. If not provided, the full debt is repaid. :param int | None account_id: The id of the account to repay the debt for. If not provided, the default account is used. :param bool submit: If ``True``, submit the transaction to the blockchain. @@ -971,7 +982,6 @@ def pay_debt( ) else: amount = ether_to_wei(amount) - tx_params = write_erc7412( self.snx, @@ -981,9 +991,7 @@ def pay_debt( ) if submit: tx_hash = self.snx.execute_transaction(tx_params) - self.logger.info( - f"Repaying debt of {amount} for account {account_id}" - ) + self.logger.info(f"Repaying debt of {amount} for account {account_id}") self.logger.info(f"payDebt tx: {tx_hash}") return tx_hash else: diff --git a/src/synthetix/pyth/pyth.py b/src/synthetix/pyth/pyth.py index eb8b5d7..1b12988 100644 --- a/src/synthetix/pyth/pyth.py +++ b/src/synthetix/pyth/pyth.py @@ -110,6 +110,15 @@ def _fetch_prices(self, feed_ids: [str], publish_time: int | None = None): try: response = requests.get(url, params, timeout=10) if response.status_code != 200: + if response.text and "Price ids not found" in response.text: + self.logger.info(f"Removing missing price feeds: {response.text}") + feed_ids = [ + feed_id + for feed_id in feed_ids + if feed_id not in response.text + ] + return self._fetch_prices(feed_ids, publish_time=publish_time) + self.logger.error(f"Error fetching latest price data: {response.text}") return None diff --git a/src/synthetix/synthetix.py b/src/synthetix/synthetix.py index 397b9a7..08a697b 100644 --- a/src/synthetix/synthetix.py +++ b/src/synthetix/synthetix.py @@ -102,6 +102,9 @@ class Synthetix: :param int perps_account_id: A default ``account_id`` for perps transactions. Setting a default will avoid the need to specify on each transaction. If not specified, the first ``account_id`` will be used. + :param list perps_disabled_markets: A list of market ids to disable for perps + trading. This is useful for disabling markets that are deprecated, or to + limit the number of markets available for trading. :param str tracking_code: Set a tracking code for trades. :param str referrer: Set a referrer address for trades. :param float max_price_impact: Max price impact setting for trades, @@ -119,6 +122,7 @@ class Synthetix: to increase the gas limit for transactions. :param bool is_fork: Set to true if the chain is a fork. This will improve the way price data is handled by requesting at the block timestamp. + :return: Synthetix class instance :rtype: Synthetix """ @@ -133,6 +137,7 @@ def __init__( network_id: int = None, core_account_id: int = None, perps_account_id: int = None, + perps_disabled_markets: list = None, tracking_code: str = DEFAULT_TRACKING_CODE, referrer: str = DEFAULT_REFERRER, max_price_impact: float = DEFAULT_SLIPPAGE, @@ -257,7 +262,7 @@ def __init__( ) self.core = Core(self, core_account_id) self.spot = Spot(self) - self.perps = Perps(self, perps_account_id) + self.perps = Perps(self, perps_account_id, perps_disabled_markets) def _load_contracts(self): """ @@ -525,7 +530,7 @@ def approve( # fix the amount amount = 2**256 - 1 if amount is None else ether_to_wei(amount) token_contract = self.web3.eth.contract( - address=token_address, abi=self.contracts['common']["ERC20"]["abi"] + address=token_address, abi=self.contracts["common"]["ERC20"]["abi"] ) tx_params = self._get_tx_params() @@ -567,7 +572,7 @@ def allowance( owner_address = self.address token_contract = self.web3.eth.contract( - address=token_address, abi=self.contracts['common']["ERC20"]["abi"] + address=token_address, abi=self.contracts["common"]["ERC20"]["abi"] ) allowance = token_contract.functions.allowance( @@ -591,7 +596,7 @@ def wrap_eth(self, amount: float, submit: bool = False) -> str: :rtype: str | dict """ value_wei = ether_to_wei(max(amount, 0)) - weth_contract = self.contracts["WETH"]['contract'] + weth_contract = self.contracts["WETH"]["contract"] if amount < 0: fn_name = "withdraw"