From 39bf8d4680d99cce65751ad5beb17499e6563768 Mon Sep 17 00:00:00 2001 From: Hieu Nguyen Date: Fri, 11 Oct 2024 12:28:47 +0300 Subject: [PATCH 1/4] Fix cloning universe --- tradeexecutor/strategy/trading_strategy_universe.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tradeexecutor/strategy/trading_strategy_universe.py b/tradeexecutor/strategy/trading_strategy_universe.py index 03129aa25..8a7f52452 100644 --- a/tradeexecutor/strategy/trading_strategy_universe.py +++ b/tradeexecutor/strategy/trading_strategy_universe.py @@ -461,7 +461,8 @@ def clone(self) -> "TradingStrategyUniverse": new_universe = Universe( time_bucket=u.time_bucket, chains=u.chains, - exchanges=u.exchanges, + exchanges=u.exchanges or set(), + exchange_universe=u.exchange_universe, pairs=u.pairs, candles=u.candles, liquidity=u.liquidity, From 9dce6df6c1a458e046b277c7fcf82228ad23e217 Mon Sep 17 00:00:00 2001 From: Hieu Nguyen Date: Tue, 15 Oct 2024 00:29:56 +0300 Subject: [PATCH 2/4] Replace hardcoded gas limits with default per chain --- .../ethereum/aave_v3/aave_v3_routing.py | 5 +- .../ethereum/one_delta/one_delta_routing.py | 5 +- tradeexecutor/ethereum/routing_state.py | 49 ++++++++++++------- .../ethereum/uniswap_v2/uniswap_v2_routing.py | 20 ++++---- .../ethereum/uniswap_v3/uniswap_v3_routing.py | 13 +++-- 5 files changed, 56 insertions(+), 36 deletions(-) diff --git a/tradeexecutor/ethereum/aave_v3/aave_v3_routing.py b/tradeexecutor/ethereum/aave_v3/aave_v3_routing.py index cbcabb59f..b1b46af6c 100644 --- a/tradeexecutor/ethereum/aave_v3/aave_v3_routing.py +++ b/tradeexecutor/ethereum/aave_v3/aave_v3_routing.py @@ -60,9 +60,10 @@ def __init__( self, pair_universe: PandasPairUniverse, tx_builder: Optional[HotWalletTransactionBuilder]=None, - swap_gas_limit=2_000_000 + swap_gas_limit=None, + approve_gas_limit=None, ): - super().__init__(pair_universe, tx_builder, swap_gas_limit) + super().__init__(pair_universe, tx_builder=tx_builder, swap_gas_limit=swap_gas_limit, approve_gas_limit=approve_gas_limit) def __repr__(self): return f"" diff --git a/tradeexecutor/ethereum/one_delta/one_delta_routing.py b/tradeexecutor/ethereum/one_delta/one_delta_routing.py index 4718afb3b..dfc9b23b6 100644 --- a/tradeexecutor/ethereum/one_delta/one_delta_routing.py +++ b/tradeexecutor/ethereum/one_delta/one_delta_routing.py @@ -72,9 +72,10 @@ def __init__( self, pair_universe: PandasPairUniverse, tx_builder: Optional[HotWalletTransactionBuilder]=None, - swap_gas_limit=2_000_000 + swap_gas_limit=None, + approve_gas_limit=None, ): - super().__init__(pair_universe, tx_builder, swap_gas_limit) + super().__init__(pair_universe, tx_builder=tx_builder, swap_gas_limit=swap_gas_limit, approve_gas_limit=approve_gas_limit) def __repr__(self): return f"" diff --git a/tradeexecutor/ethereum/routing_state.py b/tradeexecutor/ethereum/routing_state.py index 99c54952c..6b8e5daf5 100644 --- a/tradeexecutor/ethereum/routing_state.py +++ b/tradeexecutor/ethereum/routing_state.py @@ -40,9 +40,21 @@ class OutOfBalance(Exception): # Arbitrum default gas limit is 500_000 # and it is not enough ChainId.arbitrum.value: 850_000, + ChainId.polygon.value: 250_000, + ChainId.ethereum.value: 50_000, } -DEFAULT_APPROVE_GAS_LIMIT = 250_000 +DEFAULT_APPROVE_GAS_LIMIT = 50_000 + +#: How much maximum we can spend on a swap +#: +SWAP_GAS_LIMITS = { + ChainId.arbitrum.value: 200_000, + ChainId.polygon.value: 500_000, + ChainId.ethereum.value: 200_000, +} + +DEFAULT_SWAP_GAS_LIMIT = 200_000 deployment_types = UniswapV2Deployment | UniswapV3Deployment @@ -68,10 +80,12 @@ class EthereumRoutingState(RoutingState): def __init__( self, - pair_universe: PandasPairUniverse, - tx_builder: Optional[TransactionBuilder] = None, - swap_gas_limit=2_000_000, - web3: Optional[Web3] = None, + pair_universe: PandasPairUniverse, + *, + tx_builder: Optional[TransactionBuilder] = None, + swap_gas_limit: int | None = None, + approve_gas_limit: int | None = None, + web3: Optional[Web3] = None, ): """ @@ -110,7 +124,12 @@ def __init__( # router -> erc-20 mappings self.approved_routes = defaultdict(set) - self.swap_gas_limit = swap_gas_limit + + # set gas limits + if approve_gas_limit is None: + approve_gas_limit = APPROVE_GAS_LIMITS.get(self.tx_builder.chain_id, DEFAULT_APPROVE_GAS_LIMIT) + if swap_gas_limit is None: + swap_gas_limit = SWAP_GAS_LIMITS.get(self.tx_builder.chain_id, DEFAULT_SWAP_GAS_LIMIT) @abstractmethod def get_uniswap_for_pair(): @@ -210,16 +229,12 @@ def ensure_token_approved( if erc_20.functions.allowance(approve_address, router_address).call() > 0: # already approved in previous execution cycle return [] - - # Gas limit for ERC-20 approve() may vary per chain, - # see Arbitrum - gas_limit = APPROVE_GAS_LIMITS.get(self.tx_builder.chain_id, DEFAULT_APPROVE_GAS_LIMIT) # Create infinite approval tx = self.tx_builder.sign_transaction( erc_20, erc_20.functions.approve(router_address, amount), - gas_limit=gas_limit, + gas_limit=self.approve_gas_limit, gas_price_suggestion=None, asset_deltas=[], ) @@ -227,12 +242,12 @@ def ensure_token_approved( return [tx] def create_signed_transaction( - self, - contract: Contract, - swap_func: ContractFunction, - gas_limit: int, - asset_deltas: List[AssetDelta], - notes="", + self, + contract: Contract, + swap_func: ContractFunction, + gas_limit: int, + asset_deltas: List[AssetDelta], + notes="", ): signed_tx = self.tx_builder.sign_transaction( contract, diff --git a/tradeexecutor/ethereum/uniswap_v2/uniswap_v2_routing.py b/tradeexecutor/ethereum/uniswap_v2/uniswap_v2_routing.py index d0a1c305e..0cbd1a6cc 100644 --- a/tradeexecutor/ethereum/uniswap_v2/uniswap_v2_routing.py +++ b/tradeexecutor/ethereum/uniswap_v2/uniswap_v2_routing.py @@ -43,16 +43,16 @@ class UniswapV2RoutingState(EthereumRoutingState): - def __init__(self, - pair_universe: PandasPairUniverse, - tx_builder: Optional[TransactionBuilder] = None, - web3: Optional[Web3] = None, - swap_gas_limit=2_000_000): - super().__init__(pair_universe=pair_universe, - tx_builder=tx_builder, - swap_gas_limit=swap_gas_limit, - web3=web3) - + def __init__( + self, + pair_universe: PandasPairUniverse, + tx_builder: Optional[TransactionBuilder] = None, + web3: Optional[Web3] = None, + swap_gas_limit=None, + approve_gas_limit=None, + ): + super().__init__(pair_universe, tx_builder=tx_builder, swap_gas_limit=swap_gas_limit, approve_gas_limit=approve_gas_limit, web3=web3) + def __repr__(self): return f"" diff --git a/tradeexecutor/ethereum/uniswap_v3/uniswap_v3_routing.py b/tradeexecutor/ethereum/uniswap_v3/uniswap_v3_routing.py index 4871c02d8..dc5215787 100644 --- a/tradeexecutor/ethereum/uniswap_v3/uniswap_v3_routing.py +++ b/tradeexecutor/ethereum/uniswap_v3/uniswap_v3_routing.py @@ -45,11 +45,14 @@ class UniswapV3RoutingState(EthereumRoutingState): - def __init__(self, - pair_universe: PandasPairUniverse, - tx_builder: Optional[HotWalletTransactionBuilder]=None, - swap_gas_limit=2_000_000): - super().__init__(pair_universe, tx_builder, swap_gas_limit) + def __init__( + self, + pair_universe: PandasPairUniverse, + tx_builder: Optional[HotWalletTransactionBuilder]=None, + swap_gas_limit=None, + approve_gas_limit=None, + ): + super().__init__(pair_universe, tx_builder=tx_builder, swap_gas_limit=swap_gas_limit, approve_gas_limit=approve_gas_limit) def __repr__(self): return f"" From adeae7648aac2175d78bef1429520d2286a7d3bb Mon Sep 17 00:00:00 2001 From: Hieu Nguyen Date: Tue, 15 Oct 2024 01:21:37 +0300 Subject: [PATCH 3/4] Fix tests --- tradeexecutor/ethereum/routing_state.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tradeexecutor/ethereum/routing_state.py b/tradeexecutor/ethereum/routing_state.py index 6b8e5daf5..79e425d1a 100644 --- a/tradeexecutor/ethereum/routing_state.py +++ b/tradeexecutor/ethereum/routing_state.py @@ -49,8 +49,8 @@ class OutOfBalance(Exception): #: How much maximum we can spend on a swap #: SWAP_GAS_LIMITS = { - ChainId.arbitrum.value: 200_000, - ChainId.polygon.value: 500_000, + ChainId.arbitrum.value: 1_000_000, + ChainId.polygon.value: 1_000_000, ChainId.ethereum.value: 200_000, } @@ -115,21 +115,23 @@ def __init__( if tx_builder is not None: self.tx_builder = tx_builder self.web3 = self.tx_builder.web3 + self.chain_id = self.tx_builder.chain_id else: # DummyExecution model does not have a wallet # and cannot build transactions self.tx_builder = None self.hot_wallet = None self.web3 = web3 + self.chain_id = web3.eth.chain_id # router -> erc-20 mappings self.approved_routes = defaultdict(set) # set gas limits if approve_gas_limit is None: - approve_gas_limit = APPROVE_GAS_LIMITS.get(self.tx_builder.chain_id, DEFAULT_APPROVE_GAS_LIMIT) + self.approve_gas_limit = APPROVE_GAS_LIMITS.get(self.chain_id, DEFAULT_APPROVE_GAS_LIMIT) if swap_gas_limit is None: - swap_gas_limit = SWAP_GAS_LIMITS.get(self.tx_builder.chain_id, DEFAULT_SWAP_GAS_LIMIT) + self.swap_gas_limit = SWAP_GAS_LIMITS.get(self.chain_id, DEFAULT_SWAP_GAS_LIMIT) @abstractmethod def get_uniswap_for_pair(): From 680b3827542ac7a51de4df4956bf2ac157afd634 Mon Sep 17 00:00:00 2001 From: Hieu Nguyen Date: Tue, 15 Oct 2024 10:17:31 +0300 Subject: [PATCH 4/4] Raise default gas limit to higher --- tradeexecutor/ethereum/routing_state.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tradeexecutor/ethereum/routing_state.py b/tradeexecutor/ethereum/routing_state.py index 79e425d1a..2fbd7c393 100644 --- a/tradeexecutor/ethereum/routing_state.py +++ b/tradeexecutor/ethereum/routing_state.py @@ -37,14 +37,13 @@ class OutOfBalance(Exception): #: #: APPROVE_GAS_LIMITS = { - # Arbitrum default gas limit is 500_000 - # and it is not enough + # Arbitrum default gas limit is 500_000 and it is not enough ChainId.arbitrum.value: 850_000, ChainId.polygon.value: 250_000, ChainId.ethereum.value: 50_000, } -DEFAULT_APPROVE_GAS_LIMIT = 50_000 +DEFAULT_APPROVE_GAS_LIMIT = 250_000 #: How much maximum we can spend on a swap #: @@ -54,7 +53,7 @@ class OutOfBalance(Exception): ChainId.ethereum.value: 200_000, } -DEFAULT_SWAP_GAS_LIMIT = 200_000 +DEFAULT_SWAP_GAS_LIMIT = 1_000_000 deployment_types = UniswapV2Deployment | UniswapV3Deployment