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..2fbd7c393 100644 --- a/tradeexecutor/ethereum/routing_state.py +++ b/tradeexecutor/ethereum/routing_state.py @@ -37,13 +37,24 @@ 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 = 250_000 +#: How much maximum we can spend on a swap +#: +SWAP_GAS_LIMITS = { + ChainId.arbitrum.value: 1_000_000, + ChainId.polygon.value: 1_000_000, + ChainId.ethereum.value: 200_000, +} + +DEFAULT_SWAP_GAS_LIMIT = 1_000_000 + deployment_types = UniswapV2Deployment | UniswapV3Deployment @@ -68,10 +79,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, ): """ @@ -101,16 +114,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) - self.swap_gas_limit = swap_gas_limit + + # set gas limits + if approve_gas_limit is None: + self.approve_gas_limit = APPROVE_GAS_LIMITS.get(self.chain_id, DEFAULT_APPROVE_GAS_LIMIT) + if swap_gas_limit is None: + self.swap_gas_limit = SWAP_GAS_LIMITS.get(self.chain_id, DEFAULT_SWAP_GAS_LIMIT) @abstractmethod def get_uniswap_for_pair(): @@ -210,16 +230,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 +243,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"" 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,