1
1
import logging
2
- from functools import cache , cached_property , lru_cache
2
+ from functools import cache
3
3
from typing import Any , AsyncIterator , NotRequired , Sequence , TypedDict , cast
4
4
5
+ from async_lru import alru_cache
5
6
from eth_abi import decode as decode_abi
6
7
from eth_abi .exceptions import DecodingError
7
8
from eth_typing import ABIFunction , Address , HexStr
@@ -80,8 +81,14 @@ async def init(self, session: AsyncSession) -> None:
80
81
logger .info (
81
82
"%s: Contract ABIs for decoding were loaded" , self .__class__ .__name__
82
83
)
83
- self .multisend_abis : list [Sequence [ABIFunction ]] = [m async for m in self .get_multisend_abis ()]
84
- self .multisend_fn_selectors_with_abis : dict [bytes , ABIFunction ] = await self ._generate_selectors_with_abis_from_abis (self .get_multisend_abis ())
84
+ self .multisend_abis : list [Sequence [ABIFunction ]] = [
85
+ m async for m in self .get_multisend_abis ()
86
+ ]
87
+ self .multisend_fn_selectors_with_abis : dict [bytes , ABIFunction ] = (
88
+ await self ._generate_selectors_with_abis_from_abis (
89
+ self .get_multisend_abis ()
90
+ )
91
+ )
85
92
86
93
def _generate_selectors_with_abis_from_abi (
87
94
self , abi : Sequence [ABIFunction ]
@@ -112,7 +119,9 @@ async def _generate_selectors_with_abis_from_abis(
112
119
).items ()
113
120
}
114
121
115
- async def get_supported_abis (self , session : AsyncSession ) -> AsyncIterator [Sequence [ABIFunction ]]:
122
+ async def get_supported_abis (
123
+ self , session : AsyncSession
124
+ ) -> AsyncIterator [Sequence [ABIFunction ]]:
116
125
"""
117
126
:return: Every ABI in the database
118
127
"""
@@ -121,7 +130,7 @@ async def get_supported_abis(self, session: AsyncSession) -> AsyncIterator[Seque
121
130
async def get_multisend_abis (self ) -> AsyncIterator [Sequence [ABIFunction ]]:
122
131
yield get_multi_send_contract (self .dummy_w3 ).abi
123
132
124
- # @lru_cache (maxsize=2048)
133
+ @ alru_cache (maxsize = 2048 )
125
134
async def get_contract_abi (self , address : Address ) -> list [ABIFunction ] | None :
126
135
"""
127
136
Retrieves the ABI for the contract at the given address.
@@ -130,10 +139,14 @@ async def get_contract_abi(self, address: Address) -> list[ABIFunction] | None:
130
139
:return: List of ABI data if found, `None` otherwise.
131
140
"""
132
141
async with AsyncSession (get_engine (), expire_on_commit = False ) as session :
133
- return await Contract .get_abi_by_contract_address (session , HexBytes (address ))
142
+ return await Contract .get_abi_by_contract_address (
143
+ session , HexBytes (address )
144
+ )
134
145
135
- # @lru_cache(maxsize=2048)
136
- async def get_contract_fallback_function (self , address : Address ) -> ABIFunction | None :
146
+ @alru_cache (maxsize = 2048 )
147
+ async def get_contract_fallback_function (
148
+ self , address : Address
149
+ ) -> ABIFunction | None :
137
150
"""
138
151
:param address: Contract address
139
152
:return: Fallback ABIFunction if found, `None` otherwise.
@@ -149,7 +162,7 @@ async def get_contract_fallback_function(self, address: Address) -> ABIFunction
149
162
None ,
150
163
)
151
164
152
- # @lru_cache (maxsize=2048)
165
+ @ alru_cache (maxsize = 2048 )
153
166
async def get_contract_abi_selectors_with_functions (
154
167
self , address : Address
155
168
) -> dict [bytes , ABIFunction ] | None :
@@ -300,7 +313,7 @@ async def decode_parameters_data(
300
313
fn_selector = data [:4 ]
301
314
if fn_selector in self .multisend_fn_selectors_with_abis :
302
315
# If MultiSend, decode the transactions
303
- parameters [0 ]["value_decoded" ] = self .decode_multisend_data (data )
316
+ parameters [0 ]["value_decoded" ] = await self .decode_multisend_data (data )
304
317
305
318
elif (
306
319
fn_selector == self .EXEC_TRANSACTION_SELECTOR
@@ -353,10 +366,25 @@ async def decode_transaction(
353
366
:raises: CannotDecode if data cannot be decoded. You should catch this exception when using this function
354
367
:raises: UnexpectedProblemDecoding if there's an unexpected problem decoding (it shouldn't happen)
355
368
"""
356
- fn_name , decoded_transactions_with_types = await self . decode_transaction_with_types (
357
- data , address = address
369
+ fn_name , decoded_transactions_with_types = (
370
+ await self . decode_transaction_with_types ( data , address = address )
358
371
)
359
372
decoded_transactions = {
360
373
d ["name" ]: d ["value" ] for d in decoded_transactions_with_types
361
374
}
362
375
return fn_name , decoded_transactions
376
+
377
+ def add_abi (self , abi : ABIFunction ) -> bool :
378
+ """
379
+ Add a new abi without rebuilding the entire decoder
380
+
381
+ :return: True if decoder updated, False otherwise
382
+ """
383
+ updated = False
384
+ for selector , new_abi in self ._generate_selectors_with_abis_from_abi (
385
+ abi
386
+ ).items ():
387
+ if selector not in self .fn_selectors_with_abis :
388
+ self .fn_selectors_with_abis [selector ] = new_abi
389
+ updated = True
390
+ return updated
0 commit comments