Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Multi-Chain] Add config file #412

Merged
merged 28 commits into from
Nov 15, 2024
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
f8aefd5
config: fix mypy error
fhenneke Nov 4, 2024
62bbac5
transfer_file: fix lint
fhenneke Nov 4, 2024
6a973d0
delete constants.py
fhenneke Nov 4, 2024
ebabcf1
fix unit test
fhenneke Nov 4, 2024
6f6ce8b
add old default for network
fhenneke Nov 4, 2024
ff48c7b
make dune key optional for now
fhenneke Nov 4, 2024
5758534
make all secrets optional for now
fhenneke Nov 4, 2024
a66edec
Merge branch 'main' into add_config
fhenneke Nov 5, 2024
146fa65
fix merge commit
fhenneke Nov 5, 2024
f97df99
incorporate config on sippage into payment script
fhenneke Nov 5, 2024
2d5d631
Merge branch 'main' into add_config
fhenneke Nov 6, 2024
5b7a8cc
use enum and static class methods for config
fhenneke Nov 7, 2024
434bc61
fix pylint and mypy
fhenneke Nov 7, 2024
59e80a8
Merge branch 'main' into add_config
fhenneke Nov 8, 2024
0f94061
Merge branch 'main' into add_config
fhenneke Nov 8, 2024
057f2d4
Merge branch 'main' into add_config
fhenneke Nov 11, 2024
c697c01
Merge branch 'main' into add_config
fhenneke Nov 11, 2024
6be9178
fix error in test
fhenneke Nov 12, 2024
9c46d50
fix tests a bit more
fhenneke Nov 12, 2024
4652d19
Merge branch 'main' into add_config
harisang Nov 13, 2024
bfdb432
Merge branch 'main' into add_config
fhenneke Nov 13, 2024
9bafdd6
Merge branch 'main' into add_config
fhenneke Nov 14, 2024
766a91a
fix config import in test_prices
fhenneke Nov 14, 2024
d290f09
add node url for testing
fhenneke Nov 14, 2024
5a81073
add empty default node url
fhenneke Nov 14, 2024
82a8a5b
Update src/config.py
harisang Nov 15, 2024
c3ffd41
add comments for protocol fee config
fhenneke Nov 15, 2024
ac96e90
remove airdrop url from config
fhenneke Nov 15, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 3 additions & 6 deletions src/abis/load.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,10 @@
# TODO - following this issue: https://github.com/ethereum/web3.py/issues/3017
from web3.contract import Contract # type: ignore

from src.constants import PROJECT_ROOT
from src.config import config
from src.logger import set_log

ABI_PATH = PROJECT_ROOT / Path("src/abis")

WETH9_ADDRESS = Web3().to_checksum_address("0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2")

ABI_PATH = config.io_config.project_root_dir / Path("src/abis")

log = set_log(__name__)

Expand Down Expand Up @@ -65,7 +62,7 @@ def get_contract(

def weth9(web3: Optional[Web3] = None) -> Contract | Type[Contract]:
"""Returns an instance of WETH9 Contract"""
return IndexedContract.WETH9.get_contract(web3, WETH9_ADDRESS)
return IndexedContract.WETH9.get_contract(web3, config.payment_config.weth_address)


def erc20(
Expand Down
294 changes: 294 additions & 0 deletions src/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,294 @@
"""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

from eth_typing.evm import ChecksumAddress
from dotenv import load_dotenv
from dune_client.types import Address
from gnosis.eth.ethereum_network import EthereumNetwork
from web3 import Web3

load_dotenv()


class Network(Enum):
"""Network class for networks supported by the accounting."""

MAINNET = "mainnet"
GNOSIS = "gnosis"
ARBITRUM_ONE = "arbitrum"
BASE = "base"


@dataclass(frozen=True)
class RewardConfig:
"""Configuration for reward mechanism."""

reward_token_address: Address
cow_bonding_pool: Address
batch_reward_cap_upper: int
batch_reward_cap_lower: int
quote_reward_cow: int
quote_reward_cap_native: int
service_fee_factor: Fraction

@staticmethod
def from_network(network: Network) -> RewardConfig:
"""Initialize reward config for a given network."""
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:
"""Configuration for protocol and parner fees."""
harisang marked this conversation as resolved.
Show resolved Hide resolved

protocol_fee_safe: Address
partner_fee_cut: float
partner_fee_reduced_cut: float
harisang marked this conversation as resolved.
Show resolved Hide resolved
reduced_cut_address: str

@staticmethod
def from_network(network: Network) -> ProtocolFeeConfig:
"""Initialize protocol fee config for a given network."""
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:
"""Configuration for buffer accounting."""

include_slippage: bool

@staticmethod
def from_network(network: Network) -> BufferAccountingConfig:
"""Initialize buffer accounting config for a given network."""
match network:
case Network.MAINNET:
return BufferAccountingConfig(include_slippage=True)
harisang marked this conversation as resolved.
Show resolved Hide resolved
case _:
raise ValueError(
f"No buffer accounting config set up for network {network}."
)


@dataclass(frozen=True)
class OrderbookConfig:
"""Configuration for orderbook fetcher"""

prod_db_url: str
barn_db_url: str

@staticmethod
def from_env() -> OrderbookConfig:
"""Initialize orderbook config from environment variables."""
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:
"""Configuration for DuneFetcher."""

dune_api_key: str
dune_blockchain: str

@staticmethod
def from_network(network: Network) -> DuneConfig:
"""Initialize dune config for a given network."""
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:
"""Configuration for web3 node."""

node_url: str

@staticmethod
def from_network(network: Network) -> NodeConfig:
"""Initialize node config for a given network."""
# 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}"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR #430 simplifies a bit this part

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new environment variable is used now.


return NodeConfig(node_url=node_url)


@dataclass(frozen=True)
class PaymentConfig:
"""Configuration of payment."""

# pylint: disable=too-many-instance-attributes

network: EthereumNetwork
cow_token_address: Address
payment_safe_address: ChecksumAddress
signing_key: str | None
safe_queue_url: str
csv_airdrop_url: str
verification_docs_url: str
weth_address: ChecksumAddress

@staticmethod
def from_network(network: Network) -> PaymentConfig:
"""Initialize payment config for a given network."""
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 = (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we remove this? Seems like an overkill

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can remove it, as it also did not work for me when I tried it some time ago.

Generally, I think we should provide instructions as part of error messages and logging as much as possible.

f"{safe_url}/apps?appUrl=https://cloudflare-ipfs.com/ipfs/"
f"{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:
"""Configuration of input and output."""

log_config_file: Path
project_root_dir: Path
query_dir: Path
csv_output_dir: Path
dashboard_dir: Path
slack_channel: str | None
slack_token: str | None

@staticmethod
def from_env() -> IOConfig:
"""Initialize io config from environment variables."""
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:
"""Full configuration for solver accounting."""

# pylint: disable=too-many-instance-attributes

payment_config: PaymentConfig
orderbook_config: OrderbookConfig
dune_config: DuneConfig
node_config: NodeConfig
reward_config: RewardConfig
protocol_fee_config: ProtocolFeeConfig
buffer_accounting_config: BufferAccountingConfig
io_config: IOConfig

@staticmethod
def from_network(network: Network) -> AccountingConfig:
"""Initialize accounting config for a given network."""

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 = AccountingConfig.from_network(Network(os.environ.get("NETWORK", "mainnet")))

web3 = Web3(Web3.HTTPProvider(config.node_config.node_url))
56 changes: 0 additions & 56 deletions src/constants.py

This file was deleted.

Loading
Loading