From b288ecda8720420effeeca05e104b66ae83d9b31 Mon Sep 17 00:00:00 2001 From: Lesigh-3100 Date: Mon, 28 Aug 2023 14:52:03 +0300 Subject: [PATCH] Create NBTest_050_TestBancorV2.ipynb --- .../NBTest/NBTest_050_TestBancorV2.ipynb | 466 ++++++++++++++++++ 1 file changed, 466 insertions(+) create mode 100644 resources/NBTest/NBTest_050_TestBancorV2.ipynb diff --git a/resources/NBTest/NBTest_050_TestBancorV2.ipynb b/resources/NBTest/NBTest_050_TestBancorV2.ipynb new file mode 100644 index 000000000..9ad1c72ab --- /dev/null +++ b/resources/NBTest/NBTest_050_TestBancorV2.ipynb @@ -0,0 +1,466 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "84fa264b", + "metadata": { + "ExecuteTime": { + "end_time": "2023-07-09T13:54:12.577531Z", + "start_time": "2023-07-09T13:54:12.514167Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ConstantProductCurve v2.14 (23/May/2023)\n", + "CarbonBot v3-b2.2 (20/June/2023)\n", + "UniswapV2 v0.0.2 (2023-08-27)\n", + "UniswapV3 v0.0.2 (2023-08-27)\n", + "SushiswapV2 v0.0.2 (2023-08-27)\n", + "CarbonV1 v0.0.2 (2023-08-27)\n", + "BancorV3 v0.0.2 (2023-08-27)\n", + "imported m, np, pd, plt, os, sys, decimal; defined iseq, raises, require\n", + "Version = 3-b2.2 [requirements >= 3.0 is met]\n" + ] + } + ], + "source": [ + "# coding=utf-8\n", + "\"\"\"\n", + "This module contains the tests for the exchanges classes\n", + "\"\"\"\n", + "from fastlane_bot import Bot, Config\n", + "from fastlane_bot.bot import CarbonBot\n", + "from fastlane_bot.tools.cpc import ConstantProductCurve\n", + "from fastlane_bot.tools.cpc import ConstantProductCurve as CPC\n", + "from fastlane_bot.events.exchanges import UniswapV2, UniswapV3, SushiswapV2, CarbonV1, BancorV3\n", + "from fastlane_bot.events.interface import QueryInterface\n", + "from fastlane_bot.helpers.poolandtokens import PoolAndTokens\n", + "from fastlane_bot.helpers import TradeInstruction, TxReceiptHandler, TxRouteHandler, TxSubmitHandler, TxHelpers, TxHelper\n", + "from fastlane_bot.events.managers.manager import Manager\n", + "from fastlane_bot.events.interface import QueryInterface\n", + "from joblib import Parallel, delayed\n", + "from fastlane_bot.tools.cpc import ConstantProductCurve as CPC, CPCContainer, T\n", + "from dataclasses import dataclass, asdict, field\n", + "import pytest\n", + "import math\n", + "import json\n", + "print(\"{0.__name__} v{0.__VERSION__} ({0.__DATE__})\".format(CPC))\n", + "print(\"{0.__name__} v{0.__VERSION__} ({0.__DATE__})\".format(Bot))\n", + "print(\"{0.__name__} v{0.__VERSION__} ({0.__DATE__})\".format(UniswapV2))\n", + "print(\"{0.__name__} v{0.__VERSION__} ({0.__DATE__})\".format(UniswapV3))\n", + "print(\"{0.__name__} v{0.__VERSION__} ({0.__DATE__})\".format(SushiswapV2))\n", + "print(\"{0.__name__} v{0.__VERSION__} ({0.__DATE__})\".format(CarbonV1))\n", + "print(\"{0.__name__} v{0.__VERSION__} ({0.__DATE__})\".format(BancorV3))\n", + "from fastlane_bot.testing import *\n", + "from fastlane_bot.modes import triangle_single_bancor3\n", + "#plt.style.use('seaborn-dark')\n", + "plt.rcParams['figure.figsize'] = [12,6]\n", + "from fastlane_bot import __VERSION__\n", + "require(\"3.0\", __VERSION__)" + ] + }, + { + "cell_type": "markdown", + "id": "4c4e2283", + "metadata": {}, + "source": [ + "# BancorV2Test [NB050]" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "a51e5ec2", + "metadata": { + "ExecuteTime": { + "end_time": "2023-07-09T13:54:13.771032Z", + "start_time": "2023-07-09T13:54:12.517536Z" + } + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2023-08-28 12:46:38,522 [fastlane:INFO] - Time taken to add initial pools: 0.08721756935119629\n", + "2023-08-28 12:46:38,525 [fastlane:INFO] - Initializing the bot...\n", + "2023-08-28 12:46:38,689 [fastlane:INFO] - Removed 3248 unmapped uniswap_v2/sushi pools. 2086 uniswap_v2/sushi pools remaining\n", + "2023-08-28 12:46:38,690 [fastlane:INFO] - Unmapped uniswap_v2/sushi pools:\n", + "2023-08-28 12:46:38,849 [fastlane:INFO] - uniswap_v3: 0\n", + "2023-08-28 12:46:38,850 [fastlane:INFO] - uniswap_v2: 3248\n", + "2023-08-28 12:46:38,851 [fastlane:INFO] - sushiswap_v2: 0\n", + "2023-08-28 12:46:38,852 [fastlane:INFO] - uniswap_v3: 1232\n", + "2023-08-28 12:46:38,853 [fastlane:INFO] - sushiswap_v2: 106\n", + "2023-08-28 12:46:38,853 [fastlane:INFO] - uniswap_v2: 0\n", + "2023-08-28 12:46:38,854 [fastlane:INFO] - bancor_v2: 100\n", + "2023-08-28 12:46:38,854 [fastlane:INFO] - bancor_v3: 28\n", + "2023-08-28 12:46:38,855 [fastlane:INFO] - carbon_v1: 315\n", + "2023-08-28 12:46:38,890 [fastlane:INFO] - uniswap_v3_zero_liquidity_pools: 262\n", + "2023-08-28 12:46:38,891 [fastlane:INFO] - sushiswap_v2_zero_liquidity_pools: 0\n", + "2023-08-28 12:46:38,891 [fastlane:INFO] - uniswap_v2_zero_liquidity_pools: 0\n", + "2023-08-28 12:46:38,892 [fastlane:INFO] - bancor_v2_zero_liquidity_pools: 0\n", + "2023-08-28 12:46:38,892 [fastlane:INFO] - bancor_v3_zero_liquidity_pools: 43\n", + "2023-08-28 12:46:38,893 [fastlane:INFO] - carbon_v1_zero_liquidity_pools: 0\n", + "2023-08-28 12:46:38,893 [fastlane:INFO] - Removed 0 unsupported exchanges. 1781 pools remaining\n", + "2023-08-28 12:46:38,894 [fastlane:INFO] - Pools remaining per exchange:\n", + "2023-08-28 12:46:38,894 [fastlane:INFO] - sushiswap_v2: 106\n", + "2023-08-28 12:46:38,895 [fastlane:INFO] - bancor_v2: 100\n", + "2023-08-28 12:46:38,895 [fastlane:INFO] - uniswap_v3: 1232\n", + "2023-08-28 12:46:38,896 [fastlane:INFO] - uniswap_v2: 0\n", + "2023-08-28 12:46:38,897 [fastlane:INFO] - bancor_v3: 28\n", + "2023-08-28 12:46:38,897 [fastlane:INFO] - carbon_v1: 315\n" + ] + } + ], + "source": [ + "C = cfg = Config.new(config=Config.CONFIG_MAINNET)\n", + "C.DEFAULT_MIN_PROFIT_BNT = 0.02\n", + "C.DEFAULT_MIN_PROFIT = 0.02\n", + "cfg.DEFAULT_MIN_PROFIT_BNT = 0.02\n", + "cfg.DEFAULT_MIN_PROFIT = 0.02\n", + "assert (C.NETWORK == C.NETWORK_MAINNET)\n", + "assert (C.PROVIDER == C.PROVIDER_ALCHEMY)\n", + "setup_bot = CarbonBot(ConfigObj=C)\n", + "pools = None\n", + "\n", + "with open('fastlane_bot/data/tests/latest_pool_data_testing_bancor_v2.json') as f:\n", + " pools = json.load(f)\n", + "pools = [pool for pool in pools]\n", + "pools[0]\n", + "static_pools = pools\n", + "state = pools\n", + "exchanges = list({ex['exchange_name'] for ex in state})\n", + "db = QueryInterface(state=state, ConfigObj=C, exchanges=exchanges)\n", + "setup_bot.db = db\n", + "\n", + "static_pool_data_filename = \"static_pool_data\"\n", + "\n", + "static_pool_data = pd.read_csv(f\"fastlane_bot/data/{static_pool_data_filename}.csv\", low_memory=False)\n", + " \n", + "uniswap_v2_event_mappings = pd.read_csv(\"fastlane_bot/data/uniswap_v2_event_mappings.csv\", low_memory=False)\n", + " \n", + "tokens = pd.read_csv(\"fastlane_bot/data/tokens.csv\", low_memory=False)\n", + " \n", + "exchanges = \"carbon_v1,bancor_v3,uniswap_v3,uniswap_v2,sushiswap_v2\"\n", + "\n", + "exchanges = exchanges.split(\",\")\n", + "\n", + "\n", + "alchemy_max_block_fetch = 20\n", + "static_pool_data[\"cid\"] = [\n", + " cfg.w3.keccak(text=f\"{row['descr']}\").hex()\n", + " for index, row in static_pool_data.iterrows()\n", + " ]\n", + "# Filter out pools that are not in the supported exchanges\n", + "static_pool_data = [\n", + " row for index, row in static_pool_data.iterrows()\n", + " if row[\"exchange_name\"] in exchanges\n", + "]\n", + "\n", + "static_pool_data = pd.DataFrame(static_pool_data)\n", + "static_pool_data['exchange_name'].unique()\n", + "# Initialize data fetch manager\n", + "mgr = Manager(\n", + " web3=cfg.w3,\n", + " cfg=cfg,\n", + " pool_data=static_pool_data.to_dict(orient=\"records\"),\n", + " SUPPORTED_EXCHANGES=exchanges,\n", + " alchemy_max_block_fetch=alchemy_max_block_fetch,\n", + " uniswap_v2_event_mappings=uniswap_v2_event_mappings,\n", + " tokens=tokens.to_dict(orient=\"records\"),\n", + ")\n", + "\n", + "# Add initial pools for each row in the static_pool_data\n", + "start_time = time.time()\n", + "Parallel(n_jobs=-1, backend=\"threading\")(\n", + " delayed(mgr.add_pool_to_exchange)(row) for row in mgr.pool_data\n", + ")\n", + "cfg.logger.info(f\"Time taken to add initial pools: {time.time() - start_time}\")\n", + "\n", + "# check if any duplicate cid's exist in the pool data\n", + "mgr.deduplicate_pool_data()\n", + "cids = [pool[\"cid\"] for pool in mgr.pool_data]\n", + "assert len(cids) == len(set(cids)), \"duplicate cid's exist in the pool data\"\n", + "def init_bot(mgr: Manager) -> CarbonBot:\n", + " \"\"\"\n", + " Initializes the bot.\n", + "\n", + " Parameters\n", + " ----------\n", + " mgr : Manager\n", + " The manager object.\n", + "\n", + " Returns\n", + " -------\n", + " CarbonBot\n", + " The bot object.\n", + " \"\"\"\n", + " mgr.cfg.logger.info(\"Initializing the bot...\")\n", + " bot = CarbonBot(ConfigObj=mgr.cfg)\n", + " bot.db = db\n", + " bot.db.mgr = mgr\n", + " assert isinstance(\n", + " bot.db, QueryInterface\n", + " ), \"QueryInterface not initialized correctly\"\n", + " return bot\n", + "bot = init_bot(mgr)\n", + "# add data cleanup steps from main.py\n", + "bot.db.handle_token_key_cleanup()\n", + "bot.db.remove_unmapped_uniswap_v2_pools()\n", + "bot.db.remove_zero_liquidity_pools()\n", + "bot.db.remove_unsupported_exchanges()\n", + "tokens = bot.db.get_tokens()\n", + "ADDRDEC = {t.key: (t.address, int(t.decimals)) for t in tokens if not math.isnan(t.decimals)}\n", + "flashloan_tokens = bot.setup_flashloan_tokens(None)\n", + "CCm = bot.setup_CCm(None)\n", + "pools = db.get_pool_data_with_tokens()\n", + "\n", + "arb_mode = \"multi\"" + ] + }, + { + "cell_type": "markdown", + "id": "a70cf16f", + "metadata": {}, + "source": [ + "## Test_MIN_PROFIT" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "c8f41237", + "metadata": {}, + "outputs": [], + "source": [ + "assert(cfg.DEFAULT_MIN_PROFIT_BNT <= 0.02), f\"[TestMultiMode], DEFAULT_MIN_PROFIT_BNT must be <= 0.02 for this Notebook to run, currently set to {cfg.DEFAULT_MIN_PROFIT_BNT}\"\n", + "assert(C.DEFAULT_MIN_PROFIT_BNT <= 0.02), f\"[TestMultiMode], DEFAULT_MIN_PROFIT_BNT must be <= 0.02 for this Notebook to run, currently set to {cfg.DEFAULT_MIN_PROFIT_BNT}\"" + ] + }, + { + "cell_type": "markdown", + "id": "9469cd63", + "metadata": {}, + "source": [ + "## Test_Combos_and_Tokens" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "b1f40498", + "metadata": {}, + "outputs": [], + "source": [ + "arb_finder = bot._get_arb_finder(\"multi\")\n", + "finder2 = arb_finder(\n", + " flashloan_tokens=flashloan_tokens,\n", + " CCm=CCm,\n", + " mode=\"bothin\",\n", + " result=bot.AO_TOKENS,\n", + " ConfigObj=bot.ConfigObj,\n", + " )\n", + "all_tokens, combos = finder2.find_arbitrage()\n", + "assert len(all_tokens) == 971, f\"[NBTest_50_TestBancorV2] Using wrong dataset, expected 971 tokens, found {len(all_tokens)}\"\n", + "assert len(combos) == 5820, f\"[NBTest_50_TestBancorV2] Using wrong dataset, expected 5820 tokens, found {len(combos)}\"\n" + ] + }, + { + "cell_type": "markdown", + "id": "e703ba6b", + "metadata": {}, + "source": [ + "## Test_Expected_Output_BancorV2" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "86cd764b", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2023-08-28 12:46:39,290 [fastlane:ERROR] - [TODO CLEAN UP]list index out of range\n", + "2023-08-28 12:46:39,298 [fastlane:ERROR] - [TODO CLEAN UP]list index out of range\n", + "2023-08-28 12:46:39,302 [fastlane:ERROR] - [TODO CLEAN UP]list index out of range\n", + "2023-08-28 12:46:39,471 [fastlane:ERROR] - [TODO CLEAN UP]list index out of range\n", + "2023-08-28 12:46:39,478 [fastlane:ERROR] - [TODO CLEAN UP]list index out of range\n", + "2023-08-28 12:46:39,485 [fastlane:ERROR] - [TODO CLEAN UP]list index out of range\n", + "2023-08-28 12:46:39,753 [fastlane:ERROR] - [TODO CLEAN UP]list index out of range\n", + "2023-08-28 12:46:39,757 [fastlane:ERROR] - [TODO CLEAN UP]list index out of range\n", + "2023-08-28 12:46:39,992 [fastlane:ERROR] - [TODO CLEAN UP]list index out of range\n", + "2023-08-28 12:46:39,999 [fastlane:ERROR] - [TODO CLEAN UP]list index out of range\n", + "2023-08-28 12:46:40,002 [fastlane:ERROR] - [TODO CLEAN UP]list index out of range\n", + "2023-08-28 12:46:40,154 [fastlane:ERROR] - [TODO CLEAN UP]list index out of range\n", + "2023-08-28 12:46:40,161 [fastlane:ERROR] - [TODO CLEAN UP]list index out of range\n", + "2023-08-28 12:46:40,167 [fastlane:ERROR] - [TODO CLEAN UP]list index out of range\n", + "2023-08-28 12:46:40,430 [fastlane:ERROR] - [TODO CLEAN UP]list index out of range\n", + "2023-08-28 12:46:40,434 [fastlane:ERROR] - [TODO CLEAN UP]list index out of range\n" + ] + } + ], + "source": [ + "run_full = bot._run(flashloan_tokens=flashloan_tokens, CCm=CCm, arb_mode=arb_mode, data_validator=False, result=bot.XS_ARBOPPS)\n", + "arb_finder = bot._get_arb_finder(\"multi\")\n", + "finder = arb_finder(\n", + " flashloan_tokens=flashloan_tokens,\n", + " CCm=CCm,\n", + " mode=\"bothin\",\n", + " result=bot.AO_CANDIDATES,\n", + " ConfigObj=bot.ConfigObj,\n", + " )\n", + "r = finder.find_arbitrage()\n", + "arb_with_bancor_v2 = []\n", + "\n", + "for arb_opp in r:\n", + " pools = []\n", + " for pool in arb_opp[2]:\n", + " pools += [curve for curve in CCm if curve.cid == pool['cid']]\n", + " for pool in pools:\n", + " if pool.params['exchange'] == \"bancor_v2\":\n", + " arb_with_bancor_v2.append(arb_opp)\n", + "\n", + "# get specific arb for tests\n", + "\n", + "test_arb = None\n", + "\n", + "test_cids = ['0x297f9a0e8d3f57de8c62a8fde0ff09193b934ff0ae906085526f0b97b90e188a', '3743106036130323098097120681749450326076-0', '3743106036130323098097120681749450326076-1']\n", + "\n", + "for arb in arb_with_bancor_v2:\n", + " all_match = True\n", + " for pool in arb[2]:\n", + " if pool['cid'] not in test_cids:\n", + " all_match = False\n", + " \n", + " if all_match:\n", + " test_arb = arb\n", + "\n", + "(\n", + " best_profit,\n", + " best_trade_instructions_df,\n", + " best_trade_instructions_dic,\n", + " best_src_token,\n", + " best_trade_instructions,\n", + ") = test_arb\n", + "\n", + "# Order the trade instructions\n", + "(\n", + " ordered_trade_instructions_dct,\n", + " tx_in_count,\n", + ") = bot._simple_ordering_by_src_token(\n", + " best_trade_instructions_dic, best_src_token\n", + ")\n", + "\n", + "# Scale the trade instructions\n", + "ordered_scaled_dcts = bot._basic_scaling(\n", + " ordered_trade_instructions_dct, best_src_token\n", + ")\n", + "\n", + "# Convert the trade instructions\n", + "ordered_trade_instructions_objects = bot._convert_trade_instructions(\n", + " ordered_scaled_dcts\n", + ")\n", + "\n", + "# Create the tx route handler\n", + "tx_route_handler = bot.TxRouteHandlerClass(\n", + " trade_instructions=ordered_trade_instructions_objects\n", + ")\n", + "\n", + "# Aggregate the carbon trades\n", + "agg_trade_instructions = (\n", + " tx_route_handler.aggregate_carbon_trades(ordered_trade_instructions_objects)\n", + " if bot._carbon_in_trade_route(ordered_trade_instructions_objects)\n", + " else ordered_trade_instructions_objects\n", + ")\n", + "\n", + "# Calculate the trade instructions\n", + "calculated_trade_instructions = tx_route_handler.calculate_trade_outputs(\n", + " agg_trade_instructions\n", + ")\n", + "\n", + "# Aggregate multiple Bancor V3 trades into a single trade\n", + "calculated_trade_instructions = tx_route_handler.aggregate_bancor_v3_trades(\n", + " calculated_trade_instructions\n", + ")\n", + "\n", + "# Get the flashloan token\n", + "fl_token = fl_token_with_weth = calculated_trade_instructions[0].tknin_key\n", + "\n", + "# If the flashloan token is WETH, then use ETH\n", + "if fl_token == T.WETH:\n", + " fl_token = T.NATIVE_ETH\n", + "\n", + "best_profit = flashloan_tkn_profit = tx_route_handler.calculate_trade_profit(calculated_trade_instructions)\n", + "\n", + "# Use helper function to calculate profit\n", + "best_profit, flt_per_bnt, profit_usd = bot.calculate_profit(\n", + " CCm, best_profit, fl_token, fl_token_with_weth\n", + ")\n", + "\n", + "# Check if the best profit is greater than the minimum profit\n", + "if best_profit < bot.ConfigObj.DEFAULT_MIN_PROFIT:\n", + " bot.ConfigObj.logger.info(\n", + " f\"Opportunity with profit: {num_format(best_profit)} does not meet minimum profit: {self.ConfigObj.DEFAULT_MIN_PROFIT}, discarding.\"\n", + " )\n", + "\n", + "# Get the flashloan amount and token address\n", + "flashloan_amount = int(calculated_trade_instructions[0].amtin_wei)\n", + "flashloan_token_address = bot.ConfigObj.w3.toChecksumAddress(\n", + " bot.db.get_token(key=fl_token).address\n", + ")\n", + "\n", + "# Encode the trade instructions\n", + "encoded_trade_instructions = tx_route_handler.custom_data_encoder(\n", + " calculated_trade_instructions\n", + ")\n", + "\n", + "# Get the deadline\n", + "deadline = bot._get_deadline()\n", + "\n", + "# Get the route struct\n", + "route_struct = [\n", + " asdict(rs)\n", + " for rs in tx_route_handler.get_route_structs(\n", + " encoded_trade_instructions, deadline\n", + " )\n", + "]\n", + "assert arb_finder.__name__ == \"FindArbitrageMultiPairwise\", f\"[NBTest_50_TestBancorV2] Expected arb_finder class name name = FindArbitrageMultiPairwise, found {arb_finder.__name__}\"\n", + "assert len(r) == 31, f\"[NBTest_50_TestBancorV2] Expected 31 arb opps, found {len(r)}\"\n", + "assert len(arb_with_bancor_v2) == 4, f\"[NBTest_50_TestBancorV2] Expected 4 arb opps with Bancor V2 pools, found {len(arb_with_bancor_v2)}\"\n", + "assert encoded_trade_instructions[0].amtin * 10 ** 18 == flashloan_amount, f\"[NBTest_50_TestBancorV2] First trade in should match flashloan amount\"\n", + "assert route_struct[0]['customAddress'] == \"0xb1CD6e4153B2a390Cf00A6556b0fC1458C4A5533\" or route_struct[1]['customAddress'] == \"0xb1CD6e4153B2a390Cf00A6556b0fC1458C4A5533\", f\"[NBTest_50_TestBancorV2] customAddress for Bancor V2.1 trade must be converter token address, expected: 0xb1CD6e4153B2a390Cf00A6556b0fC1458C4A5533 for one address, found: {route_struct[0]['customAddress']} and {route_struct[1]['customAddress']}\"" + ] + } + ], + "metadata": { + "jupytext": { + "formats": "ipynb,py:light" + }, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.1" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}