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

Class TxHelpers Revision #529

Closed
wants to merge 25 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
8c74ffa
add fusionx
NIXBNT Apr 8, 2024
c381de8
clean up multicarbon handling
NIXBNT Apr 8, 2024
e0ad695
Remove extras & update name
Lesigh-3100 Apr 9, 2024
ec1f451
Revise Class TxHelpers
Apr 9, 2024
9df1461
Remove submithandler.py
Apr 9, 2024
e16f725
remove unused list
NIXBNT Apr 9, 2024
c69a25f
Merge branch 'main' into update_fusionx
zavelevsky Apr 10, 2024
de0697c
Merge pull request #525 from bancorprotocol/update_fusionx
zavelevsky Apr 10, 2024
ce69428
Bump version [skip ci]
actions-user Apr 10, 2024
a51c14c
Update changelog [skip ci]
actions-user Apr 10, 2024
78fa219
github action support for testing more networks [skip ci]
zavelevsky Apr 11, 2024
831a842
Merge branch 'gh_actions_envs' of https://github.com/bancorprotocol/f…
Apr 11, 2024
621c0d3
Reverse previous commit
Apr 11, 2024
05b63da
Merge branch 'tx-helpers-revision' of https://github.com/bancorprotoc…
Apr 11, 2024
6e04ec0
Merge branch 'develop' of https://github.com/bancorprotocol/fastlane-…
Apr 11, 2024
3ff4ea5
Update web3.py's version
Apr 11, 2024
d5f6407
Update poetry lock file
Apr 11, 2024
4721e6d
Debug GitHub's testing environment
Apr 11, 2024
7be3385
Debug
Apr 11, 2024
fed59d1
Debug
Apr 11, 2024
a5c2716
Revert previous commits
Apr 11, 2024
42a028b
Merge branch 'tx-helpers-revision' of https://github.com/bancorprotoc…
Apr 11, 2024
9e81e61
Move tests 059, 062 and 069 to a folder which they will not be execut…
Apr 11, 2024
31a1162
Undo recent stuff
Apr 11, 2024
51d20ed
Merge branch 'tx-helpers-revision' of https://github.com/bancorprotoc…
Apr 11, 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
51 changes: 8 additions & 43 deletions fastlane_bot/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,10 @@
from fastlane_bot.helpers import (
TxRouteHandler,
TxHelpers,
TxHelpersBase,
TradeInstruction,
Univ3Calculator,
add_wrap_or_unwrap_trades_to_route,
split_carbon_trades,
submit_transaction_tenderly
split_carbon_trades
)
from fastlane_bot.helpers.routehandler import maximize_last_trade_per_tkn
from fastlane_bot.tools.cpc import ConstantProductCurve as CPC, CPCContainer, T
Expand Down Expand Up @@ -95,7 +93,7 @@ class CarbonBotBase:
the database manager.
TxRouteHandlerClass
ditto (default: TxRouteHandler).
TxHelpersClass: class derived from TxHelpersBase
TxHelpersClass:
ditto (default: TxHelpers).

"""
Expand All @@ -119,8 +117,6 @@ def __post_init__(self):
if self.ConfigObj is None:
self.ConfigObj = Config()

self.c = self.ConfigObj

assert (
self.polling_interval is None
), "polling_interval is now a parameter to run"
Expand All @@ -129,10 +125,7 @@ def __post_init__(self):
self.TxRouteHandlerClass = TxRouteHandler

if self.TxHelpersClass is None:
self.TxHelpersClass = TxHelpers(ConfigObj=self.ConfigObj)
assert issubclass(
self.TxHelpersClass.__class__, TxHelpersBase
), f"TxHelpersClass not derived from TxHelpersBase {self.TxHelpersClass}"
self.TxHelpersClass = TxHelpers(cfg=self.ConfigObj)

self.db = QueryInterface(ConfigObj=self.ConfigObj)
self.RUN_FLASHLOAN_TOKENS = [*self.ConfigObj.CHAIN_FLASHLOAN_TOKENS.values()]
Expand Down Expand Up @@ -1042,19 +1035,6 @@ def _handle_trade_instructions(

route_struct_maximized = maximize_last_trade_per_tkn(route_struct=route_struct_processed)

# Get the cids
cids = list({ti["cid"] for ti in best_trade_instructions_dic})

# Check if the network is tenderly and submit the transaction accordingly
if self.ConfigObj.NETWORK == self.ConfigObj.NETWORK_TENDERLY:
return submit_transaction_tenderly(
cfg=self.ConfigObj,
flashloan_struct=flashloan_struct,
route_struct=route_struct_maximized,
src_amount=flashloan_amount_wei,
src_address=flashloan_token_address,
)

# Log the route_struct
self.handle_logging_for_trade_instructions(
4, # The log id
Expand All @@ -1065,18 +1045,13 @@ def _handle_trade_instructions(
best_trade_instructions_dic=best_trade_instructions_dic,
)

# Get the tx helpers class
tx_helpers = TxHelpers(ConfigObj=self.ConfigObj)

# Return the validate and submit transaction
return tx_helpers.validate_and_submit_transaction(
return self.TxHelpersClass.validate_and_submit_transaction(
route_struct=route_struct_maximized,
src_amt=flashloan_amount_wei,
src_address=flashloan_token_address,
expected_profit_gastkn=best_profit_gastkn,
expected_profit_usd=best_profit_usd,
safety_override=False,
verbose=True,
log_object=log_dict,
flashloan_struct=flashloan_struct,
)
Expand Down Expand Up @@ -1320,33 +1295,23 @@ def run_single_mode(
randomizer=randomizer,
replay_mode=replay_mode,
)
if tx_hash and tx_hash[0]:
if tx_hash:
self.ConfigObj.logger.info(
f"[bot.run_single_mode] Arbitrage executed [hash={tx_hash}]"
)

# Write the tx hash to a file in the logging_path directory
if self.logging_path:
filename = f"successful_tx_hash_{datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}.txt"
print(f"Writing tx_hash hash {tx_hash} to {filename}")
self.ConfigObj.logger.info(f"Writing tx hash {tx_hash} to {filename}")
with open(f"{self.logging_path}/{filename}", "w") as f:

# if isinstance(tx_hash[0], AttributeDict):
# f.write(str(tx_hash[0]))
# else:
for record in tx_hash:
f.write("\n")
f.write("\n")
try:
json.dump(record, f, indent=4)
except:
f.write(str(record))
f.write(tx_hash)

except self.NoArbAvailable as e:
self.ConfigObj.logger.warning(f"[NoArbAvailable] {e}")
except Exception as e:
self.ConfigObj.logger.error(f"[bot:run:single] {e}")
raise
raise e

def _ensure_connection(self, tenderly_fork: str):
"""
Expand Down
24 changes: 9 additions & 15 deletions fastlane_bot/config/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,25 +266,10 @@ class ConfigNetwork(ConfigBase):

# DEFAULT VALUES SECTION
#######################################################################################
UNIV3_FEE_LIST = [80, 100, 250, 450, 500, 2500, 3000, 10000]
MIN_BNT_LIQUIDITY = 2_000_000_000_000_000_000
DEFAULT_GAS = 950_000
DEFAULT_GAS_PRICE = 0
DEFAULT_GAS_PRICE_OFFSET = 1.09
DEFAULT_GAS_SAFETY_OFFSET = 25_000
DEFAULT_POLL_INTERVAL = 12
DEFAULT_BLOCKTIME_DEVIATION = 13 * 500 * 100 # 10 block time deviation
DEFAULT_MAX_SLIPPAGE = Decimal("1") # 1%
_PROJECT_PATH = os.path.normpath(f"{os.getcwd()}") # TODO: FIX THIS
DEFAULT_CURVES_DATAFILE = os.path.normpath(
f"{_PROJECT_PATH}/carbon/data/curves.csv.gz"
)
CARBON_STRATEGY_CHUNK_SIZE = 200
Q96 = Decimal("2") ** Decimal("96")
DEFAULT_TIMEOUT = 60
CARBON_FEE = Decimal("0.002")
BANCOR_V3_FEE = Decimal("0.0")
DEFAULT_REWARD_PERCENT = Decimal("0.5")
LIMIT_BANCOR3_FLASHLOAN_TOKENS = True
DEFAULT_MIN_PROFIT_GAS_TOKEN = Decimal("0.02")

Expand All @@ -308,6 +293,15 @@ class ConfigNetwork(ConfigBase):
GAS_TKN_IN_FLASHLOAN_TOKENS = None
IS_NO_FLASHLOAN_AVAILABLE = False

# HOOKS
#######################################################################################
@staticmethod
def gas_strategy(web3):
return {
"maxFeePerGas": web3.eth.gas_price,
"maxPriorityFeePerGas": web3.eth.max_priority_fee
}

@classmethod
def new(cls, network=None):
"""
Expand Down
73 changes: 17 additions & 56 deletions fastlane_bot/config/provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,51 +112,20 @@ def __init__(self, network: ConfigNetwork, **kwargs):
self.connection.connect_network()
self.w3 = self.connection.web3
self.w3_async = self.connection.w3_async
self.LOCAL_ACCOUNT = self.w3.eth.account.from_key(ETH_PRIVATE_KEY_BE_CAREFUL)


if network.NETWORK in [N.NETWORK_BASE, N.NETWORK_ETHEREUM, N.NETWORK_FANTOM, N.NETWORK_MANTLE]:
self.CARBON_CONTROLLER_CONTRACT = self.w3.eth.contract(
address=network.CARBON_CONTROLLER_ADDRESS,
abi=CARBON_CONTROLLER_ABI,
)
self.BANCOR_ARBITRAGE_CONTRACT = self.w3.eth.contract(
address=self.w3.to_checksum_address(network.FASTLANE_CONTRACT_ADDRESS),
abi=FAST_LANE_CONTRACT_ABI,
)

if network.GAS_ORACLE_ADDRESS:
self.GAS_ORACLE_CONTRACT = self.w3_async.eth.contract(
address=network.GAS_ORACLE_ADDRESS,
abi=GAS_ORACLE_ABI
)

self.BANCOR_ARBITRAGE_CONTRACT = self.w3.eth.contract(
address=self.w3.to_checksum_address(N.FASTLANE_CONTRACT_ADDRESS),
abi=FAST_LANE_CONTRACT_ABI,
)

if network.NETWORK in N.NETWORK_ETHEREUM:
self.BANCOR_NETWORK_INFO_CONTRACT = self.w3.eth.contract(
address=network.BANCOR_V3_NETWORK_INFO_ADDRESS,
abi=BANCOR_V3_NETWORK_INFO_ABI,
if N.GAS_ORACLE_ADDRESS:
self.GAS_ORACLE_CONTRACT = self.w3.eth.contract(
address=N.GAS_ORACLE_ADDRESS,
abi=GAS_ORACLE_ABI,
)
self.ARB_CONTRACT_VERSION = self.BANCOR_ARBITRAGE_CONTRACT.caller.version()

else:
self.CARBON_CONTROLLER_CONTRACT = None
self.ARB_CONTRACT_VERSION = 10

if self.BANCOR_ARBITRAGE_CONTRACT is not None:
try:
(
reward_percent,
max_profit,
) = self.BANCOR_ARBITRAGE_CONTRACT.caller.rewards()
self.ARB_REWARD_PERCENTAGE = str(int(reward_percent) / 1000000)
self.ARB_MAX_PROFIT = 1000000 # This is no longer used
except:
self.ARB_REWARD_PERCENTAGE = "0.5"
else:
self.ARB_REWARD_PERCENTAGE = "0.5"

self.EXPECTED_GAS_MODIFIER = "0.85"
self.ARB_CONTRACT_VERSION = self.BANCOR_ARBITRAGE_CONTRACT.caller.version()
self.ARB_REWARDS_PPM = self.BANCOR_ARBITRAGE_CONTRACT.caller.rewards()[0]


class _ConfigProviderTenderly(ConfigProvider):
Expand All @@ -182,26 +151,20 @@ def __init__(self, network: ConfigNetwork, **kwargs):
)
self.connection.connect_network()
self.w3 = self.connection.web3
self.LOCAL_ACCOUNT = self.w3.eth.account.from_key(ETH_PRIVATE_KEY_BE_CAREFUL)

self.BANCOR_NETWORK_INFO_CONTRACT = self.w3.eth.contract(
address=N.BANCOR_V3_NETWORK_INFO_ADDRESS,
abi=BANCOR_V3_NETWORK_INFO_ABI,
)
self.CARBON_CONTROLLER_CONTRACT = self.w3.eth.contract(
address=N.CARBON_CONTROLLER_ADDRESS,
abi=CARBON_CONTROLLER_ABI,
)
self.BANCOR_ARBITRAGE_CONTRACT = self.w3.eth.contract(
address=self.w3.to_checksum_address(N.FASTLANE_CONTRACT_ADDRESS),
abi=FAST_LANE_CONTRACT_ABI,
)
self.ARB_CONTRACT_VERSION = self.BANCOR_ARBITRAGE_CONTRACT.caller.version()

reward_percent, max_profit = self.BANCOR_ARBITRAGE_CONTRACT.caller.rewards()
if N.GAS_ORACLE_ADDRESS:
self.GAS_ORACLE_CONTRACT = self.w3.eth.contract(
address=N.GAS_ORACLE_ADDRESS,
abi=GAS_ORACLE_ABI,
)

self.ARB_REWARD_PERCENTAGE = str(int(reward_percent) / 1000000)
self.ARB_MAX_PROFIT = str(int(max_profit) / (10**18))
self.ARB_CONTRACT_VERSION = self.BANCOR_ARBITRAGE_CONTRACT.caller.version()
self.ARB_REWARDS_PPM = self.BANCOR_ARBITRAGE_CONTRACT.caller.rewards()[0]


class _ConfigProviderInfura(ConfigProvider):
Expand Down Expand Up @@ -232,6 +195,4 @@ def __init__(self, network: ConfigNetwork, **kwargs):
# raise NotImplementedError("Infura not implemented")
self.connection = None
self.w3 = None
self.BANCOR_NETWORK_INFO_CONTRACT = None
self.CARBON_CONTROLLER_CONTRACT = None
self.BANCOR_ARBITRAGE_CONTRACT = None
90 changes: 5 additions & 85 deletions fastlane_bot/events/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -578,8 +578,8 @@ def get_config(

Parameters
----------
default_min_profit_bnt : int or Decimal
The default minimum profit in BNT.
default_min_profit_gas_token : int or Decimal
The default minimum profit in the gas token.
limit_bancor3_flashloan_tokens : bool
Whether to limit the flashloan tokens to Bancor v3 pools.
loglevel : str
Expand Down Expand Up @@ -2001,93 +2001,13 @@ def handle_tokens_csv(mgr, prefix_path, read_only: bool = False):
)


def self_funding_warning_sequence(cfg):
"""
This function initiates a warning sequence if the user has specified to use their own funds.

:param cfg: the config object

"""
cfg.logger.info(
f"\n\n*********************************************************************************\n********************************* WARNING *********************************\n\n"
)
cfg.logger.info(
f"Arbitrage bot is set to use its own funds instead of using Flashloans.\n\n***** This could put your funds at risk. ******\nIf you did not mean to use this mode, cancel the bot now.\n\nOtherwise, the bot will submit token approvals IRRESPECTIVE OF CURRENT GAS PRICE for each token specified in Flashloan tokens.\n\n*********************************************************************************"
)
time.sleep(5)
cfg.logger.info(f"Submitting approvals in 15 seconds")
time.sleep(5)
cfg.logger.info(f"Submitting approvals in 10 seconds")
time.sleep(5)
cfg.logger.info(f"Submitting approvals in 5 seconds")
time.sleep(5)
cfg.logger.info(
f"*********************************************************************************\n\nSelf-funding mode activated."
)
cfg.logger.info(
f"""\n\n
_____
|A . | _____
| /.\ ||A ^ | _____
|(_._)|| / \ ||A _ | _____
| | || \ / || ( ) ||A_ _ |
|____V|| . ||(_'_)||( v )|
|____V|| | || \ / |
|____V|| . |
|____V|
\n\n"""
)


def find_unapproved_tokens(tokens: List, cfg, tx_helpers) -> List:
"""
This function checks if tokens have been previously approved from the wallet address to the Arbitrage contract.
If they are not already approved, it will submit approvals for each token specified in Flashloan tokens.
:param tokens: the list of tokens to check/approve
:param cfg: the config object
:param tx_helpers: the TxHelpers instantiated class

returns: List of tokens that have not been approved

"""
unapproved_tokens = []
for tkn in tokens:
if not tx_helpers.check_if_token_approved(token_address=tkn):
unapproved_tokens.append(tkn)
return unapproved_tokens


def check_and_approve_tokens(tokens: List, cfg) -> bool:
def check_and_approve_tokens(cfg: Config, tokens: List):
"""
This function checks if tokens have been previously approved from the wallet address to the Arbitrage contract.
If they are not already approved, it will submit approvals for each token specified in Flashloan tokens.

:param tokens: the list of tokens to check/approve
:param cfg: the config object
:param tokens: the list of tokens to check/approve

"""

tokens = [tkn for tkn in tokens if tkn != cfg.NATIVE_GAS_TOKEN_ADDRESS]

self_funding_warning_sequence(cfg=cfg)
tx_helpers = TxHelpers(ConfigObj=cfg)
unapproved_tokens = find_unapproved_tokens(
tokens=tokens, cfg=cfg, tx_helpers=tx_helpers
)

if len(unapproved_tokens) == 0:
return True

for _tkn in unapproved_tokens:
tx = tx_helpers.approve_token_for_arb_contract(token_address=_tkn)
if tx is not None:
continue
else:
assert (
False
), f"Failed to approve token: {_tkn}. This can be fixed by approving manually, or restarting the bot to try again."

unapproved_tokens = find_unapproved_tokens(
tokens=unapproved_tokens, cfg=cfg, tx_helpers=tx_helpers
)
return len(unapproved_tokens) == 0
TxHelpers(cfg=cfg).check_and_approve_tokens(tokens=tokens)
5 changes: 0 additions & 5 deletions fastlane_bot/helpers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,7 @@
"""
from .tradeinstruction import TradeInstruction
from .routehandler import TxRouteHandler, RouteStruct
from .submithandler import submit_transaction_tenderly
from .txhelpers import TxHelpers
from .univ3calc import Univ3Calculator
from .wrap_unwrap_processor import add_wrap_or_unwrap_trades_to_route
from .carbon_trade_splitter import split_carbon_trades
TxHelpersBase = TxHelpers



Loading
Loading