1
1
from time import sleep
2
+ from typing import Optional
2
3
3
4
from web3 .eth import Eth
4
5
from web3 .exceptions import ContractLogicError
5
- from web3 .types import FilterParams , LogReceipt
6
+ from web3 .types import FilterParams , LogReceipt , CallOverride , BlockIdentifier , TxParams
7
+
8
+ from IceCreamSwapWeb3 import Web3Advanced
6
9
7
10
8
11
def exponential_retry (func_name : str = None ):
9
12
def wrapper (func ):
10
- def inner (* args , no_retry = False , ** kwargs ):
13
+ def inner (* args , no_retry : bool = False , ** kwargs ):
11
14
if no_retry :
12
15
return func (* args , ** kwargs )
13
16
@@ -33,9 +36,10 @@ def inner(*args, no_retry=False, **kwargs):
33
36
34
37
35
38
class EthAdvanced (Eth ):
36
- # todo: implement multicall
39
+ w3 : Web3Advanced
40
+
37
41
METHODS_TO_RETRY = [
38
- 'fee_history' , 'call' , ' create_access_list' , 'estimate_gas' ,
42
+ 'fee_history' , 'create_access_list' , 'estimate_gas' ,
39
43
'get_transaction' , 'get_raw_transaction' , 'get_raw_transaction_by_block' ,
40
44
'send_transaction' , 'send_raw_transaction' , 'get_block' , 'get_balance' ,
41
45
'get_code' , 'get_transaction_count' , 'get_transaction_receipt' ,
@@ -50,23 +54,6 @@ class EthAdvanced(Eth):
50
54
'max_priority_fee' , 'mining' , 'syncing'
51
55
]
52
56
53
- FILTER_RANGES_TO_TRY = sorted ([
54
- 10_000 ,
55
- 5_000 ,
56
- 2_000 ,
57
- 1_000 ,
58
- 500 ,
59
- 200 ,
60
- 100 ,
61
- 50 ,
62
- 20 ,
63
- 10 ,
64
- 5 ,
65
- 2 ,
66
- 1
67
- ], reverse = True )
68
- assert FILTER_RANGES_TO_TRY [- 1 ] == 1
69
-
70
57
def __init__ (self , w3 ):
71
58
super ().__init__ (w3 = w3 )
72
59
@@ -75,8 +62,6 @@ def __init__(self, w3):
75
62
76
63
self .chain_id_cached = super ()._chain_id ()
77
64
78
- self .filter_block_range = self ._find_max_filter_range ()
79
-
80
65
def _wrap_methods_with_retry (self ):
81
66
for method_name in self .METHODS_TO_RETRY :
82
67
method = getattr (self , method_name )
@@ -87,6 +72,26 @@ def _wrap_methods_with_retry(self):
87
72
wrapped_prop = property (exponential_retry (func_name = prop_name )(prop .fget ))
88
73
setattr (self .__class__ , prop_name , wrapped_prop )
89
74
75
+ def call (
76
+ self ,
77
+ transaction : TxParams ,
78
+ block_identifier : Optional [BlockIdentifier ] = None ,
79
+ state_override : Optional [CallOverride ] = None ,
80
+ ccip_read_enabled : Optional [bool ] = None ,
81
+ no_retry : bool = None ,
82
+ ):
83
+ if "no_retry" in transaction :
84
+ no_retry = transaction ["no_retry" ]
85
+ del transaction ["no_retry" ]
86
+
87
+ return exponential_retry (func_name = "call" )(super ().call )(
88
+ transaction = transaction ,
89
+ block_identifier = block_identifier ,
90
+ state_override = state_override ,
91
+ ccip_read_enabled = ccip_read_enabled ,
92
+ no_retry = no_retry ,
93
+ )
94
+
90
95
def get_logs (self , filter_params : FilterParams , show_progress_bar = False , p_bar = None ) -> list [LogReceipt ]:
91
96
# getting the respective block numbers, could be block hashes or strings like "latest"
92
97
from_block = filter_params ["fromBlock" ]
@@ -108,10 +113,13 @@ def get_logs(self, filter_params: FilterParams, show_progress_bar=False, p_bar=N
108
113
p_bar = tqdm (total = num_blocks )
109
114
110
115
# if we already know that the filter range is too large, split it
111
- if num_blocks > self .filter_block_range :
116
+ filter_block_range = self .w3 .filter_block_range
117
+ if filter_block_range == 0 :
118
+ raise Exception ("RPC does not support eth_getLogs" )
119
+ if num_blocks > filter_block_range :
112
120
results = []
113
- for filter_start in range (from_block , to_block + 1 , self . filter_block_range ):
114
- filter_end = min (filter_start + self . filter_block_range - 1 , to_block )
121
+ for filter_start in range (from_block , to_block + 1 , filter_block_range ):
122
+ filter_end = min (filter_start + filter_block_range - 1 , to_block )
115
123
partial_filter = filter_params .copy ()
116
124
partial_filter ["fromBlock" ] = filter_start
117
125
partial_filter ["toBlock" ] = filter_end
@@ -150,23 +158,6 @@ def get_logs(self, filter_params: FilterParams, show_progress_bar=False, p_bar=N
150
158
p_bar .update (num_blocks )
151
159
return events
152
160
153
- def _find_max_filter_range (self ):
154
- current_block = self .block_number
155
- for filter_range in self .FILTER_RANGES_TO_TRY :
156
- try :
157
- # getting logs from the 0 address as it does not emit any logs.
158
- # This way we can test the maximum allowed filter range without getting back a ton of logs
159
- result = self ._get_logs ({
160
- "address" : "0x0000000000000000000000000000000000000000" ,
161
- "fromBlock" : current_block - 5 - filter_range + 1 ,
162
- "toBlock" : current_block - 5 ,
163
- })
164
- assert result == []
165
- return filter_range
166
- except Exception :
167
- pass
168
- raise ValueError ("Unable to use eth_getLogs" )
169
-
170
161
def _chain_id (self ):
171
162
# usually this causes an RPC call and is used in every eth_call. Getting it once in the init and then not again.
172
163
return self .chain_id_cached
0 commit comments