From 5b7a8cc99f55f162d04b18abfed4fbcd8b011406 Mon Sep 17 00:00:00 2001 From: Felix Henneke Date: Thu, 7 Nov 2024 11:19:38 +0100 Subject: [PATCH] use enum and static class methods for config this addresses review comments - uses an enum instead of a string for better checking of network values - move initialization of configs into individual classes: use from_network and from_env to initialize classes --- src/config.py | 262 +++++++++++++++++++++++++++++++------------------- 1 file changed, 163 insertions(+), 99 deletions(-) diff --git a/src/config.py b/src/config.py index 869ea21c..7667203f 100644 --- a/src/config.py +++ b/src/config.py @@ -1,7 +1,10 @@ """Config for solver accounting.""" +from __future__ import annotations + import os from dataclasses import dataclass +from enum import Enum from fractions import Fraction from pathlib import Path @@ -14,6 +17,13 @@ load_dotenv() +class Network(Enum): + MAINNET = "mainnet" + GNOSIS = "gnosis" + ARBITRUM_ONE = "arbitrum" + BASE = "base" + + @dataclass(frozen=True) class RewardConfig: """Configuration for reward mechanism.""" @@ -26,6 +36,26 @@ class RewardConfig: quote_reward_cap_native: int service_fee_factor: Fraction + @staticmethod + def from_network(network: Network) -> RewardConfig: + match network: + case Network.MAINNET: + return RewardConfig( + reward_token_address=Address( + "0xDEf1CA1fb7FBcDC777520aa7f396b4E015F497aB" + ), + batch_reward_cap_upper=12 * 10**15, + batch_reward_cap_lower=10 * 10**15, + quote_reward_cow=6 * 10**18, + quote_reward_cap_native=6 * 10**14, + service_fee_factor=Fraction(15, 100), + cow_bonding_pool=Address( + "0x5d4020b9261f01b6f8a45db929704b0ad6f5e9e6" + ), + ) + case _: + raise ValueError(f"No reward config set up for network {network}.") + @dataclass(frozen=True) class ProtocolFeeConfig: @@ -36,6 +66,23 @@ class ProtocolFeeConfig: partner_fee_reduced_cut: float reduced_cut_address: str + @staticmethod + def from_network(network: Network) -> ProtocolFeeConfig: + match network: + case Network.MAINNET: + return ProtocolFeeConfig( + protocol_fee_safe=Address( + "0xB64963f95215FDe6510657e719bd832BB8bb941B" + ), + partner_fee_cut=0.15, + partner_fee_reduced_cut=0.10, + reduced_cut_address="0x63695Eee2c3141BDE314C5a6f89B98E62808d716", + ) + case _: + raise ValueError( + f"No protocol fee config set up for network {network}." + ) + @dataclass(frozen=True) class BufferAccountingConfig: @@ -43,6 +90,16 @@ class BufferAccountingConfig: include_slippage: bool + @staticmethod + def from_network(network: Network) -> BufferAccountingConfig: + match network: + case Network.MAINNET: + return BufferAccountingConfig(include_slippage=True) + case _: + raise ValueError( + f"No buffer accounting config set up for network {network}." + ) + @dataclass(frozen=True) class OrderbookConfig: @@ -51,6 +108,13 @@ class OrderbookConfig: prod_db_url: str barn_db_url: str + @staticmethod + def from_env() -> OrderbookConfig: + prod_db_url = os.environ.get("PROD_DB_URL", "") + barn_db_url = os.environ.get("BARN_DB_URL", "") + + return OrderbookConfig(prod_db_url=prod_db_url, barn_db_url=barn_db_url) + @dataclass(frozen=True) class DuneConfig: @@ -59,6 +123,15 @@ class DuneConfig: dune_api_key: str dune_blockchain: str + @staticmethod + def from_network(network: Network) -> DuneConfig: + dune_api_key = os.environ.get("DUNE_API_KEY", "") + match network: + case Network.MAINNET: + return DuneConfig(dune_api_key=dune_api_key, dune_blockchain="ethereum") + case _: + raise ValueError(f"No dune config set up for network {network}.") + @dataclass(frozen=True) class NodeConfig: @@ -66,6 +139,14 @@ class NodeConfig: node_url: str + @staticmethod + def from_network(network: Network) -> NodeConfig: + # Found this exposed infura key on https://rpc.info/ + infura_key = os.environ.get("INFURA_KEY", "9aa3d95b3bc440fa88ea12eaa4456161") + node_url = f"https://{network}.infura.io/v3/{infura_key}" + + return NodeConfig(node_url=node_url) + @dataclass(frozen=True) class PaymentConfig: @@ -82,6 +163,53 @@ class PaymentConfig: verification_docs_url: str weth_address: ChecksumAddress + @staticmethod + def from_network(network: Network) -> PaymentConfig: + signing_key = os.getenv("PROPOSER_PK") + if signing_key == "": + signing_key = None + + docs_url = "https://www.notion.so/cownation/Solver-Payouts-3dfee64eb3d449ed8157a652cc817a8c" + + network_short_name = { + Network.MAINNET: "eth", + Network.GNOSIS: "gno", + } + + match network: + case Network.MAINNET: + payment_safe_address = Web3.to_checksum_address( + os.environ.get( + "SAFE_ADDRESS", "0xA03be496e67Ec29bC62F01a428683D7F9c204930" + ) + ) + short_name = network_short_name[network] + csv_app_hash = "Qme49gESuwpSvwANmEqo34yfCkzyQehooJ5yL7aHmKJnpZ" + safe_url = ( + f"https://app.safe.global/{short_name}:{payment_safe_address}" + ) + airdrop_url = f"{safe_url}/apps?appUrl=https://cloudflare-ipfs.com/ipfs/{csv_app_hash}/" + safe_queue_url = f"{safe_url}/transactions/queue" + + return PaymentConfig( + network=EthereumNetwork.MAINNET, + cow_token_address=Address( + "0xDEf1CA1fb7FBcDC777520aa7f396b4E015F497aB" + ), + payment_safe_address=Web3.to_checksum_address( + "0xA03be496e67Ec29bC62F01a428683D7F9c204930" + ), + signing_key=signing_key, + safe_queue_url=safe_queue_url, + csv_airdrop_url=airdrop_url, + verification_docs_url=docs_url, + weth_address=Web3.to_checksum_address( + "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2" + ), + ) + case _: + raise ValueError(f"No payment config set up for network {network}.") + @dataclass(frozen=True) class IOConfig: @@ -95,6 +223,27 @@ class IOConfig: slack_channel: str | None slack_token: str | None + @staticmethod + def from_env(): + slack_channel = os.getenv("SLACK_CHANNEL", None) + slack_token = os.getenv("SLACK_TOKEN", None) + + project_root_dir = Path(__file__).parent.parent + file_out_dir = project_root_dir / Path("out") + log_config_file = project_root_dir / Path("logging.conf") + query_dir = project_root_dir / Path("queries") + dashboard_dir = project_root_dir / Path("dashboards/solver-rewards-accounting") + + return IOConfig( + project_root_dir=project_root_dir, + log_config_file=log_config_file, + query_dir=query_dir, + csv_output_dir=file_out_dir, + dashboard_dir=dashboard_dir, + slack_channel=slack_channel, + slack_token=slack_token, + ) + @dataclass(frozen=True) class AccountingConfig: @@ -111,107 +260,22 @@ class AccountingConfig: buffer_accounting_config: BufferAccountingConfig io_config: IOConfig + @staticmethod + def from_network(network: Network) -> AccountingConfig: + """Get config for specified network.""" -def get_accounting_config(network: str) -> AccountingConfig: - """Get config for specified network.""" - - # pylint: disable=too-many-locals - - project_root_dir = Path(__file__).parent.parent - file_out_dir = project_root_dir / Path("out") - log_config_file = project_root_dir / Path("logging.conf") - query_dir = project_root_dir / Path("queries") - dashboard_dir = project_root_dir / Path("dashboards/solver-rewards-accounting") - - docs_url = "https://www.notion.so/cownation/Solver-Payouts-3dfee64eb3d449ed8157a652cc817a8c" - - # Secrets - - # Found this exposed infura key on https://rpc.info/ - infura_key = os.environ.get("INFURA_KEY", "9aa3d95b3bc440fa88ea12eaa4456161") - - dune_api_key = os.environ.get("DUNE_API_KEY", "") - - prod_db_url = os.environ.get("PROD_DB_URL", "") - barn_db_url = os.environ.get("BARN_DB_URL", "") - - signing_key = os.getenv("PROPOSER_PK") - if signing_key == "": - signing_key = None - - slack_channel = os.getenv("SLACK_CHANNEL", None) - slack_token = os.getenv("SLACK_TOKEN", None) - - node_url = f"https://{network}.infura.io/v3/{infura_key}" - - # - payment_safe_address = Web3.to_checksum_address( - os.environ.get("SAFE_ADDRESS", "0xA03be496e67Ec29bC62F01a428683D7F9c204930") - ) - short_name = { - "mainnet": "eth", - "rinkeby": "rin", - "gnosis": "gno", - "goerli": "gor", - }[network] - csv_app_hash = "Qme49gESuwpSvwANmEqo34yfCkzyQehooJ5yL7aHmKJnpZ" - safe_url = f"https://app.safe.global/{short_name}:{payment_safe_address}" - airdrop_url = ( - f"{safe_url}/apps?appUrl=https://cloudflare-ipfs.com/ipfs/{csv_app_hash}/" - ) - safe_queue_url = f"{safe_url}/transactions/queue" - - result = AccountingConfig( - payment_config=PaymentConfig( - network=EthereumNetwork.MAINNET, - cow_token_address=Address("0xDEf1CA1fb7FBcDC777520aa7f396b4E015F497aB"), - payment_safe_address=Web3.to_checksum_address( - "0xA03be496e67Ec29bC62F01a428683D7F9c204930" - ), - signing_key=signing_key, - safe_queue_url=safe_queue_url, - csv_airdrop_url=airdrop_url, - verification_docs_url=docs_url, - weth_address=Web3.to_checksum_address( - "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2" - ), - ), - orderbook_config=OrderbookConfig( - prod_db_url=prod_db_url, - barn_db_url=barn_db_url, - ), - dune_config=DuneConfig(dune_api_key=dune_api_key, dune_blockchain="ethereum"), - node_config=NodeConfig(node_url=node_url), - reward_config=RewardConfig( - reward_token_address=Address("0xDEf1CA1fb7FBcDC777520aa7f396b4E015F497aB"), - batch_reward_cap_upper=12 * 10**15, - batch_reward_cap_lower=10 * 10**15, - quote_reward_cow=6 * 10**18, - quote_reward_cap_native=6 * 10**14, - service_fee_factor=Fraction(15, 100), - cow_bonding_pool=Address("0x5d4020b9261f01b6f8a45db929704b0ad6f5e9e6"), - ), - protocol_fee_config=ProtocolFeeConfig( - protocol_fee_safe=Address("0xB64963f95215FDe6510657e719bd832BB8bb941B"), - partner_fee_cut=0.15, - partner_fee_reduced_cut=0.10, - reduced_cut_address="0x63695Eee2c3141BDE314C5a6f89B98E62808d716", - ), - buffer_accounting_config=BufferAccountingConfig(include_slippage=True), - io_config=IOConfig( - project_root_dir=project_root_dir, - log_config_file=log_config_file, - query_dir=query_dir, - csv_output_dir=file_out_dir, - dashboard_dir=dashboard_dir, - slack_channel=slack_channel, - slack_token=slack_token, - ), - ) - - return result + return AccountingConfig( + payment_config=PaymentConfig.from_network(network), + orderbook_config=OrderbookConfig.from_env(), + dune_config=DuneConfig.from_network(network), + node_config=NodeConfig.from_network(network), + reward_config=RewardConfig.from_network(network), + protocol_fee_config=ProtocolFeeConfig.from_network(network), + buffer_accounting_config=BufferAccountingConfig.from_network(network), + io_config=IOConfig.from_env(), + ) -config = get_accounting_config(os.environ.get("NETWORK", "mainnet")) +config = AccountingConfig.from_network(Network(os.environ.get("NETWORK", "mainnet"))) web3 = Web3(Web3.HTTPProvider(config.node_config.node_url))