diff --git a/fastlane_bot/config/constants.py b/fastlane_bot/config/constants.py index 7f9fd5631..f3b4fe59d 100644 --- a/fastlane_bot/config/constants.py +++ b/fastlane_bot/config/constants.py @@ -22,3 +22,183 @@ CARBON_V1_NAME = "carbon_v1" VELOCIMETER_V2_NAME = "velocimeter_v2" SOLIDLY_V2_NAME = "solidly_v2" + +ARGUMENTS = [ + ("--alchemy_max_block_fetch", {"type": int, "help": "Max number of blocks to fetch from alchemy"}), + ("--arb_mode", {"type": str, "help": "See arb_mode in bot.py", "choices": ["single", "multi", "triangle", "multi_triangle", "b3_two_hop", "multi_pairwise_pol", "multi_pairwise_all"]}), + ("--backdate_pools", {"type": bool, "help": "Set to False for faster testing / debugging"}), + ("--blockchain", {"type": str, "help": "A blockchain from the list. Blockchains not in this list do not have a deployed Fast Lane contract and are not supported.", "choices": ["ethereum", "coinbase_base", "fantom", "mantle"]}), + ("--cache_latest_only", {"type": bool, "help": "Set to True for production. Set to False for testing / debugging"}), + ("--default_min_profit_gas_token", {"type": float, "help": "Set to the default minimum profit in gas token."}), + ("--exchanges", {"type": str, "help": "Exchanges to arb against. Comma separated exchanges."}), + ("--flashloan_tokens", {"type": str, "help": "The --flashloan_tokens flag refers to those token denominations which the bot can take a flashloan in. Commma separated token addresses"}), + ("--increment_blocks", {"type": int, "help": "If tenderly_fork_id is set, this is the number of blocks to increment the block number by for each iteration."}), + ("--increment_time", {"type": int, "help": "If tenderly_fork_id is set, this is the number of seconds to increment the fork time by for each iteration."}), + ("--is_args_test", {"type": bool, "help": "The logging path."}), + ("--limit_bancor3_flashloan_tokens", {"type": bool, "help": "Only applies if arb_mode is `bancor_v3` or `b3_two_hop`."}), + ("--logging_path", {"type": str, "help": "The logging path."}), + ("--loglevel", {"type": str, "choices": ["DEBUG", "INFO", "WARNING", "ERROR"], "help": "The logging level."}), + ("--n_jobs", {"type": int, "help": "Number of parallel jobs to run"}), + ("--polling_interval", {"type": int, "help": "Polling interval in seconds."}), + ("--pool_data_update_frequency", {"type": int, "help": "How frequently pool data should be updated, in main loop iterations."}), + ("--prefix_path", {"type": str, "help": "Prefixes the path to the write folders (used for deployment)"}), + ("--randomizer", {"type": int, "help": "Set to the number of arb opportunities to pick from."}), + ("--read_only", {"type": bool, "help": "If True, the bot will skip all operations which write to disk. Use this flag if you're running the bot in an environment with restricted write permissions."}), + ("--reorg_delay", {"type": int, "help": "Number of blocks delayed to avoid reorgs"}), + ("--replay_from_block", {"type": int, "help": "Set to a block number to replay from that block."}), + ("--rpc_url", {"type": str, "help": "Custom RPC URL. If not set, the bot will use the default Alchemy RPC URL for the blockchain (if available)."}), + ("--run_data_validator", {"type": bool, "help": "Set to True for debugging / testing. Set to False for production."}), + ("--self_fund", {"type": bool, "help": "If True, the bot will attempt to submit arbitrage transactions using funds in your wallet when possible."}), + ("--static_pool_data_filename", {"type": str, "help": "Filename of the static pool data."}), + ("--target_tokens", {"type": str, "help": "A comma-separated string of tokens to target."}), + ("--tenderly_event_exchanges", {"type": str, "help": "A comma-separated string of exchanges to include for the Tenderly event fetcher."}), + ("--tenderly_fork_id", {"type": str, "help": "Set to a Tenderly fork id."}), + ("--timeout", {"type": int, "help": "Set to the timeout in seconds. Set to None for no timeout."}), + ("--use_cached_events", {"type": bool, "help": "Set to True for debugging / testing. Set to False for production."}), + ("--use_specific_exchange_for_target_tokens", {"type": str, "help": "If an exchange is specified, this will limit the scope of tokens to the tokens found on the exchange"}), + ("--version_check_frequency", {"type": int, "help": "How frequently pool data should be updated, in main loop iterations."}), +] + +# Default configuration for each blockchain +BLOCKCHAIN_DEFAULTS = { + "ethereum": { + "alchemy_max_block_fetch":2000, + "arb_mode":'multi_pairwise_all', + "backdate_pools":'False', + "blockchain":'ethereum', + "cache_latest_only":'True', + "default_min_profit_gas_token":0.01, + "exchanges":'balancer,bancor_pol,bancor_v2,bancor_v3,carbon_v1_forks,solidly_v2_forks,uniswap_v2_forks,uniswap_v3_forks', + "flashloan_tokens":'0x514910771AF9Ca656af840dff83E8264EcF986CA,0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE,0x1F573D6Fb3F13d689FF844B4cE37794d79a7FF1C,0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599,0x6B175474E89094C44Da98b954EedeAC495271d0F,0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48,0xdAC17F958D2ee523a2206206994597C13D831ec7,0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', + "increment_blocks":1, + "increment_time":1, + "is_args_test":'False', + "limit_bancor3_flashloan_tokens":'True', + "logging_path":'', + "loglevel":'INFO', + "n_jobs":-1, + "polling_interval":1, + "pool_data_update_frequency":-1, + "prefix_path":'', + "randomizer":3, + "read_only":'True', + "reorg_delay":0, + "replay_from_block":None, + "rpc_url":None, + "run_data_validator":'False', + "self_fund":'False', + "static_pool_data_filename":'static_pool_data', + "target_tokens":None, + "tenderly_event_exchanges":'pancakeswap_v2,pancakeswap_v3', + "tenderly_fork_id":None, + "timeout":None, + "use_cached_events":'False', + "use_specific_exchange_for_target_tokens":None, + "version_check_frequency":1, + }, + "coinbase_base": { + "alchemy_max_block_fetch":2000, + "arb_mode":'multi_pairwise_all', + "backdate_pools":'False', + "blockchain":'coinbase_base', + "cache_latest_only":'True', + "default_min_profit_gas_token":0.00001, + "exchanges":'balancer,carbon_v1_forks,solidly_v2_forks,uniswap_v2_forks,uniswap_v3_forks', + "flashloan_tokens":'0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE,0x4200000000000000000000000000000000000006,0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913,0xd9aAEc86B65D86f6A7B5B1b0c42FFA531710b6CA', + "increment_blocks":1, + "increment_time":1, + "is_args_test":'False', + "limit_bancor3_flashloan_tokens":'True', + "logging_path":'', + "loglevel":'INFO', + "n_jobs":-1, + "polling_interval":1, + "pool_data_update_frequency":-1, + "prefix_path":'', + "randomizer":3, + "read_only":'True', + "reorg_delay":0, + "replay_from_block":None, + "rpc_url":None, + "run_data_validator":'False', + "self_fund":'False', + "static_pool_data_filename":'static_pool_data', + "target_tokens":None, + "tenderly_event_exchanges":'pancakeswap_v2,pancakeswap_v3', + "tenderly_fork_id":None, + "timeout":None, + "use_cached_events":'False', + "use_specific_exchange_for_target_tokens":None, + "version_check_frequency":1, + }, + "fantom": { + "alchemy_max_block_fetch":1000, + "arb_mode":'multi_pairwise_all', + "backdate_pools":'False', + "blockchain":'fantom', + "cache_latest_only":'True', + "default_min_profit_gas_token":0.01, + "exchanges":'beethovenx,carbon_v1_forks,solidly_v2_forks,uniswap_v2_forks,uniswap_v3_forks', + "flashloan_tokens":'0x21be370D5312f44cB42ce377BC9b8a0cEF1A4C83,0x04068DA6C83AFCFA0e13ba15A6696662335D5B75,0x321162Cd933E2Be498Cd2267a90534A804051b11,0x28a92dde19D9989F39A49905d7C9C2FAc7799bDf,0x1B6382DBDEa11d97f24495C9A90b7c88469134a4,0x8D11eC38a3EB5E956B052f67Da8Bdc9bef8Abf3E,0x74b23882a30290451A17c44f4F05243b6b58C76d,0x049d68029688eAbF473097a2fC38ef61633A3C7A,0x82f0B8B456c1A451378467398982d4834b6829c1', + "increment_blocks":1, + "increment_time":1, + "is_args_test":'False', + "limit_bancor3_flashloan_tokens":'True', + "logging_path":'', + "loglevel":'INFO', + "n_jobs":-1, + "polling_interval":1, + "pool_data_update_frequency":-1, + "prefix_path":'', + "randomizer":3, + "read_only":'True', + "reorg_delay":0, + "replay_from_block":None, + "rpc_url":None, + "run_data_validator":'False', + "self_fund":'False', + "static_pool_data_filename":'static_pool_data', + "target_tokens":None, + "tenderly_event_exchanges":'pancakeswap_v2,pancakeswap_v3', + "tenderly_fork_id":None, + "timeout":None, + "use_cached_events":'False', + "use_specific_exchange_for_target_tokens":None, + "version_check_frequency":1, + }, + "mantle": { + "alchemy_max_block_fetch":1000, + "arb_mode":'multi_pairwise_all', + "backdate_pools":'False', + "blockchain":'mantle', + "cache_latest_only":'True', + "default_min_profit_gas_token":0.00001, + "exchanges":'carbon_v1_forks,solidly_v2_forks,uniswap_v2_forks,uniswap_v3_forks', + "flashloan_tokens":'0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8', + "increment_blocks":1, + "increment_time":1, + "is_args_test":'False', + "limit_bancor3_flashloan_tokens":'True', + "logging_path":'', + "loglevel":'INFO', + "n_jobs":-1, + "polling_interval":1, + "pool_data_update_frequency":-1, + "prefix_path":'', + "randomizer":3, + "read_only":'True', + "reorg_delay":0, + "replay_from_block":None, + "rpc_url":None, + "run_data_validator":'False', + "self_fund":'True', + "static_pool_data_filename":'static_pool_data', + "target_tokens":None, + "tenderly_event_exchanges":'pancakeswap_v2,pancakeswap_v3', + "tenderly_fork_id":None, + "timeout":None, + "use_cached_events":'False', + "use_specific_exchange_for_target_tokens":None, + "version_check_frequency":1, + }, +} diff --git a/fastlane_bot/config/network.py b/fastlane_bot/config/network.py index d29b765a0..9a24d1c0d 100644 --- a/fastlane_bot/config/network.py +++ b/fastlane_bot/config/network.py @@ -346,9 +346,7 @@ def __post_init__(self): df=self.network_df, fork_name=S.UNISWAP_V3 ) self.SOLIDLY_FEE_MAPPING = get_fee_map(df=self.network_df, fork_name=S.SOLIDLY_V2) - self.UNI_V2_FORKS = [key for key in self.UNI_V2_ROUTER_MAPPING.keys()] + [ - "uniswap_v2" - ] + self.UNI_V2_FORKS = [key for key in self.UNI_V2_ROUTER_MAPPING.keys()] self.UNI_V3_FORKS = [key for key in self.UNI_V3_ROUTER_MAPPING.keys()] self.SOLIDLY_V2_ROUTER_MAPPING = get_fork_map( diff --git a/fastlane_bot/data/multichain_addresses.csv b/fastlane_bot/data/multichain_addresses.csv index ce5ed8167..55e6c9677 100644 --- a/fastlane_bot/data/multichain_addresses.csv +++ b/fastlane_bot/data/multichain_addresses.csv @@ -49,7 +49,6 @@ sushiswap_v3,core,uniswap_v3,0xc35DADB65012eC5796536bD9864eD8773aBc74C4,N/A,,, fraxswap_v2,dogechain,uniswap_v2,0x67b7DA7c0564c6aC080f0A6D9fB4675e52E6bF1d,0x0f6A5c5F341791e897eB1FB8fE8B4e30EC4F9bDf,,, balancer,ethereum,balancer,BALANCER_VAULT_ADDRESS,0xBA12222222228d8Ba445958a75a0704d566BF2C8,0,0, carbon_v1,ethereum,carbon_v1,0xC537e898CD774e2dCBa3B14Ea6f34C93d5eA45e1,0xC537e898CD774e2dCBa3B14Ea6f34C93d5eA45e1,NA,17087375, -altered_carbon,ethereum,carbon_v1,0xA31ac5a9077d8EE58F4cd0011C315552De29542B,0xA31ac5a9077d8EE58F4cd0011C315552De29542B,NA,19375311, fraxswap_v2,ethereum,uniswap_v2,0x43eC799eAdd63848443E2347C49f5f52e8Fe0F6f,0xC14d550632db8592D1243Edc8B95b0Ad06703867,,, pancakeswap_v2,ethereum,uniswap_v2,0x1097053Fd2ea711dad45caCcc45EfF7548fCB362,0xEfF92A263d31888d860bD50809A8D171709b7b1c,0.0025,15614590, pancakeswap_v3,ethereum,uniswap_v3,0x0BFbCF9fa4f9C56B0F40a671Ad40E0805A091865,0x1b81D678ffb9C0263b24A97847620C99d213eB14,NA,16950686, diff --git a/main.py b/main.py index 5c9c86bdf..987bce6ef 100644 --- a/main.py +++ b/main.py @@ -9,6 +9,7 @@ from fastlane_bot.exceptions import AsyncUpdateRetryException, ReadOnlyException, FlashloanUnavailableException from fastlane_bot.events.version_utils import check_version_requirements from fastlane_bot.tools.cpc import T +from fastlane_bot.config.constants import BLOCKCHAIN_DEFAULTS, ARGUMENTS check_version_requirements(required_version="6.11.0", package_name="web3") @@ -107,14 +108,35 @@ def int_or_none(x): return args +def setup_arguments(parser, arguments): + for name, options in arguments: + parser.add_argument(name, **options) -def main(args: argparse.Namespace) -> None: +def apply_blockchain_defaults(args): + blockchain = args.blockchain + if blockchain not in BLOCKCHAIN_DEFAULTS.keys(): + raise ValueError("Blockchain defaults not established - please update in to constants.py") + else: + defaults = BLOCKCHAIN_DEFAULTS.get(blockchain, {}) + + # Iterate over the defaults and set them if they weren't specified by the user + for arg, default_value in defaults.items(): + if getattr(args, arg, None) is None: + setattr(args, arg, default_value) + +def main() -> None: """ Main function for running the fastlane bot. Args: args: Command line arguments. See the argparse.ArgumentParser in the __main__ block for details. """ + parser = argparse.ArgumentParser(description="Blockchain-specific configuration.") + # Establish appropriate arguments + setup_arguments(parser, ARGUMENTS) + args = parser.parse_args() + # Apply all other default arguments for that blockchain + apply_blockchain_defaults(args) args = process_arguments(args) if args.replay_from_block or args.tenderly_fork_id: @@ -203,7 +225,7 @@ def main(args: argparse.Namespace) -> None: arb_mode: {args.arb_mode} blockchain: {args.blockchain} default_min_profit_gas_token: {args.default_min_profit_gas_token} - exchanges: {exchanges} + exchanges: {sorted(exchanges)} flashloan_tokens: {args.flashloan_tokens} target_tokens: {args.target_tokens} use_specific_exchange_for_target_tokens: {args.use_specific_exchange_for_target_tokens} @@ -592,184 +614,4 @@ def run_async_update_with_retries(mgr, current_block, logging_path, max_retries= if __name__ == "__main__": - parser = argparse.ArgumentParser() - parser.add_argument( - "--cache_latest_only", - default='True', - help="Set to True for production. Set to False for testing / debugging", - ) - parser.add_argument( - "--backdate_pools", - default='False', - help="Set to False for faster testing / debugging", - ) - parser.add_argument( - "--static_pool_data_filename", - default="static_pool_data", - help="Filename of the static pool data.", - ) - parser.add_argument( - "--arb_mode", - default="multi_pairwise_all", - help="See arb_mode in bot.py", - choices=[ - "single", - "multi", - "triangle", - "multi_triangle", - "b3_two_hop", - "multi_pairwise_pol", - "multi_pairwise_all", - ], - ) - parser.add_argument( - "--flashloan_tokens", - default=f"{T.LINK},{T.NATIVE_ETH},{T.BNT},{T.WBTC},{T.DAI},{T.USDC},{T.USDT},{T.WETH}", - help="The --flashloan_tokens flag refers to those token denominations which the bot can take " - "a flash loan in.", - ) - parser.add_argument( - "--n_jobs", default=-1, help="Number of parallel jobs to run" - ) - parser.add_argument( - "--exchanges", - default="carbon_v1,bancor_v3,bancor_v2,bancor_pol,uniswap_v3,uniswap_v2,sushiswap_v2,balancer,pancakeswap_v2,pancakeswap_v3", - help="Comma separated external exchanges.", - ) - parser.add_argument( - "--polling_interval", - default=1, - help="Polling interval in seconds", - ) - parser.add_argument( - "--alchemy_max_block_fetch", - default=2000, - help="Max number of blocks to fetch from alchemy", - ) - parser.add_argument( - "--reorg_delay", - default=0, - help="Number of blocks delayed to avoid reorgs", - ) - parser.add_argument( - "--logging_path", default="", help="The logging path." - ) - parser.add_argument( - "--loglevel", - default="INFO", - choices=["DEBUG", "INFO", "WARNING", "ERROR"], - help="The logging level.", - ) - parser.add_argument( - "--use_cached_events", - default='False', - help="Set to True for debugging / testing. Set to False for production.", - ) - parser.add_argument( - "--run_data_validator", - default='False', - help="Set to True for debugging / testing. Set to False for production.", - ) - parser.add_argument( - "--randomizer", - default="3", - help="Set to the number of arb opportunities to pick from.", - ) - parser.add_argument( - "--limit_bancor3_flashloan_tokens", - default='True', - help="Only applies if arb_mode is `bancor_v3` or `b3_two_hop`.", - ) - parser.add_argument( - "--default_min_profit_gas_token", - default="0.01", - help="Set to the default minimum profit in gas token.", - ) - parser.add_argument( - "--timeout", - default=None, - help="Set to the timeout in seconds. Set to None for no timeout.", - ) - parser.add_argument( - "--target_tokens", - default=None, - help="A comma-separated string of tokens to target.", - ) - parser.add_argument( - "--replay_from_block", - default=None, - help="Set to a block number to replay from that block.", - ) - parser.add_argument( - "--tenderly_fork_id", - default=None, - help="Set to a Tenderly fork id.", - ) - parser.add_argument( - "--tenderly_event_exchanges", - default="pancakeswap_v2,pancakeswap_v3", - help="A comma-separated string of exchanges to include for the Tenderly event fetcher.", - ) - parser.add_argument( - "--increment_time", - default=1, - help="If tenderly_fork_id is set, this is the number of seconds to increment the fork time by for each iteration.", - ) - parser.add_argument( - "--increment_blocks", - default=1, - help="If tenderly_fork_id is set, this is the number of blocks to increment the block number " - "by for each iteration.", - ) - parser.add_argument( - "--blockchain", - default="ethereum", - help="A blockchain from the list. Blockchains not in this list do not have a deployed Fast Lane contract and are not supported.", - choices=["ethereum", "coinbase_base", "fantom", "mantle"], - ) - parser.add_argument( - "--pool_data_update_frequency", - default=-1, - help="How frequently pool data should be updated, in main loop iterations.", - ) - parser.add_argument( - "--use_specific_exchange_for_target_tokens", - default=None, - help="If an exchange is specified, this will limit the scope of tokens to the tokens found on the exchange", - ) - parser.add_argument( - "--prefix_path", - default="", - help="Prefixes the path to the write folders (used for deployment)", - ) - parser.add_argument( - "--version_check_frequency", - default=1, - help="How frequently pool data should be updated, in main loop iterations.", - ) - parser.add_argument( - "--self_fund", - default='False', - help="If True, the bot will attempt to submit arbitrage transactions using funds in your " - "wallet when possible.", - ) - parser.add_argument( - "--read_only", - default='True', - help="If True, the bot will skip all operations which write to disk. Use this flag if you're " - "running the bot in an environment with restricted write permissions.", - ) - parser.add_argument( - "--is_args_test", - default='False', - help="The logging path.", - ) - parser.add_argument( - "--rpc_url", - default=None, - help="Custom RPC URL. If not set, the bot will use the default Alchemy RPC URL for the blockchain (if available).", - ) - - # Process the arguments - args = parser.parse_args() - main(args) + main()