web3 7.6.0__py3-none-any.whl → 7.6.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,42 @@
1
+ """
2
+ Generated by `compile_contracts.py` script.
3
+ Compiled with Solidity v0.8.28.
4
+ """
5
+
6
+ # source: web3/_utils/contract_sources/AmbiguousFunctionContract.sol:AmbiguousFunctionContract # noqa: E501
7
+ AMBIGUOUS_FUNCTION_CONTRACT_BYTECODE = "0x6080604052348015600e575f5ffd5b5061044a8061001c5f395ff3fe608060405234801561000f575f5ffd5b506004361061003f575f3560e01c80631626ba7e1461004357806320c13b0b14610073578063d482bb47146100a3575b5f5ffd5b61005d60048036038101906100589190610293565b6100c1565b60405161006a9190610305565b60405180910390f35b61008d6004803603810190610088919061031e565b6100cb565b60405161009a9190610305565b60405180910390f35b6100ab6100d6565b6040516100b891906103f4565b60405180910390f35b5f5f905092915050565b5f6001905092915050565b60606040518060400160405280600581526020017f76616c6964000000000000000000000000000000000000000000000000000000815250905090565b5f604051905090565b5f5ffd5b5f5ffd5b5f819050919050565b61013681610124565b8114610140575f5ffd5b50565b5f813590506101518161012d565b92915050565b5f5ffd5b5f5ffd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6101a58261015f565b810181811067ffffffffffffffff821117156101c4576101c361016f565b5b80604052505050565b5f6101d6610113565b90506101e2828261019c565b919050565b5f67ffffffffffffffff8211156102015761020061016f565b5b61020a8261015f565b9050602081019050919050565b828183375f83830152505050565b5f610237610232846101e7565b6101cd565b9050828152602081018484840111156102535761025261015b565b5b61025e848285610217565b509392505050565b5f82601f83011261027a57610279610157565b5b813561028a848260208601610225565b91505092915050565b5f5f604083850312156102a9576102a861011c565b5b5f6102b685828601610143565b925050602083013567ffffffffffffffff8111156102d7576102d6610120565b5b6102e385828601610266565b9150509250929050565b5f819050919050565b6102ff816102ed565b82525050565b5f6020820190506103185f8301846102f6565b92915050565b5f5f604083850312156103345761033361011c565b5b5f83013567ffffffffffffffff81111561035157610350610120565b5b61035d85828601610266565b925050602083013567ffffffffffffffff81111561037e5761037d610120565b5b61038a85828601610266565b9150509250929050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f6103c682610394565b6103d0818561039e565b93506103e08185602086016103ae565b6103e98161015f565b840191505092915050565b5f6020820190508181035f83015261040c81846103bc565b90509291505056fea2646970667358221220baaf91e0e0589f566caa06e4f8fa283b865412d3e3c1dc1eca705cc8ad7f393764736f6c634300081c0033" # noqa: E501
8
+ AMBIGUOUS_FUNCTION_CONTRACT_RUNTIME = "0x608060405234801561000f575f5ffd5b506004361061003f575f3560e01c80631626ba7e1461004357806320c13b0b14610073578063d482bb47146100a3575b5f5ffd5b61005d60048036038101906100589190610293565b6100c1565b60405161006a9190610305565b60405180910390f35b61008d6004803603810190610088919061031e565b6100cb565b60405161009a9190610305565b60405180910390f35b6100ab6100d6565b6040516100b891906103f4565b60405180910390f35b5f5f905092915050565b5f6001905092915050565b60606040518060400160405280600581526020017f76616c6964000000000000000000000000000000000000000000000000000000815250905090565b5f604051905090565b5f5ffd5b5f5ffd5b5f819050919050565b61013681610124565b8114610140575f5ffd5b50565b5f813590506101518161012d565b92915050565b5f5ffd5b5f5ffd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6101a58261015f565b810181811067ffffffffffffffff821117156101c4576101c361016f565b5b80604052505050565b5f6101d6610113565b90506101e2828261019c565b919050565b5f67ffffffffffffffff8211156102015761020061016f565b5b61020a8261015f565b9050602081019050919050565b828183375f83830152505050565b5f610237610232846101e7565b6101cd565b9050828152602081018484840111156102535761025261015b565b5b61025e848285610217565b509392505050565b5f82601f83011261027a57610279610157565b5b813561028a848260208601610225565b91505092915050565b5f5f604083850312156102a9576102a861011c565b5b5f6102b685828601610143565b925050602083013567ffffffffffffffff8111156102d7576102d6610120565b5b6102e385828601610266565b9150509250929050565b5f819050919050565b6102ff816102ed565b82525050565b5f6020820190506103185f8301846102f6565b92915050565b5f5f604083850312156103345761033361011c565b5b5f83013567ffffffffffffffff81111561035157610350610120565b5b61035d85828601610266565b925050602083013567ffffffffffffffff81111561037e5761037d610120565b5b61038a85828601610266565b9150509250929050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f6103c682610394565b6103d0818561039e565b93506103e08185602086016103ae565b6103e98161015f565b840191505092915050565b5f6020820190508181035f83015261040c81846103bc565b90509291505056fea2646970667358221220baaf91e0e0589f566caa06e4f8fa283b865412d3e3c1dc1eca705cc8ad7f393764736f6c634300081c0033" # noqa: E501
9
+ AMBIGUOUS_FUNCTION_CONTRACT_ABI = [
10
+ {
11
+ "inputs": [
12
+ {"internalType": "bytes32", "name": "message", "type": "bytes32"},
13
+ {"internalType": "bytes", "name": "signature", "type": "bytes"},
14
+ ],
15
+ "name": "isValidSignature",
16
+ "outputs": [{"internalType": "uint256", "name": "result", "type": "uint256"}],
17
+ "stateMutability": "view",
18
+ "type": "function",
19
+ },
20
+ {
21
+ "inputs": [
22
+ {"internalType": "bytes", "name": "message", "type": "bytes"},
23
+ {"internalType": "bytes", "name": "signature", "type": "bytes"},
24
+ ],
25
+ "name": "isValidSignature",
26
+ "outputs": [{"internalType": "uint256", "name": "result", "type": "uint256"}],
27
+ "stateMutability": "view",
28
+ "type": "function",
29
+ },
30
+ {
31
+ "inputs": [],
32
+ "name": "isValidSignature",
33
+ "outputs": [{"internalType": "string", "name": "result", "type": "string"}],
34
+ "stateMutability": "view",
35
+ "type": "function",
36
+ },
37
+ ]
38
+ AMBIGUOUS_FUNCTION_CONTRACT_DATA = {
39
+ "bytecode": AMBIGUOUS_FUNCTION_CONTRACT_BYTECODE,
40
+ "bytecode_runtime": AMBIGUOUS_FUNCTION_CONTRACT_RUNTIME,
41
+ "abi": AMBIGUOUS_FUNCTION_CONTRACT_ABI,
42
+ }
web3/_utils/contracts.py CHANGED
@@ -335,7 +335,7 @@ def validate_payable(transaction: TxParams, abi_callable: ABICallable) -> None:
335
335
 
336
336
 
337
337
  def parse_block_identifier(
338
- w3: "Web3", block_identifier: BlockIdentifier
338
+ w3: "Web3", block_identifier: Optional[BlockIdentifier]
339
339
  ) -> BlockIdentifier:
340
340
  if block_identifier is None:
341
341
  return w3.eth.default_block
@@ -14,6 +14,7 @@ from typing import (
14
14
 
15
15
  from eth_typing import (
16
16
  ABI,
17
+ ABIFunction,
17
18
  ChecksumAddress,
18
19
  )
19
20
  from eth_utils import (
@@ -21,9 +22,8 @@ from eth_utils import (
21
22
  )
22
23
  from eth_utils.abi import (
23
24
  abi_to_signature,
25
+ filter_abi_by_type,
24
26
  get_abi_input_names,
25
- get_abi_input_types,
26
- get_all_function_abis,
27
27
  )
28
28
  from eth_utils.toolz import (
29
29
  partial,
@@ -34,8 +34,6 @@ from hexbytes import (
34
34
 
35
35
  from web3._utils.abi import (
36
36
  fallback_func_abi_exists,
37
- filter_by_types,
38
- get_abi_element_signature,
39
37
  get_name_from_abi_element_identifier,
40
38
  receive_func_abi_exists,
41
39
  )
@@ -93,6 +91,7 @@ from web3.contract.utils import (
93
91
  from web3.exceptions import (
94
92
  ABIEventNotFound,
95
93
  ABIFunctionNotFound,
94
+ MismatchedABI,
96
95
  NoABIEventsFound,
97
96
  NoABIFound,
98
97
  NoABIFunctionsFound,
@@ -108,8 +107,9 @@ from web3.types import (
108
107
  TxParams,
109
108
  )
110
109
  from web3.utils.abi import (
110
+ _filter_by_argument_count,
111
111
  _get_any_abi_signature_with_name,
112
- filter_abi_by_type,
112
+ _mismatched_abi_error_diagnosis,
113
113
  get_abi_element,
114
114
  )
115
115
 
@@ -123,26 +123,7 @@ class AsyncContractEvent(BaseContractEvent):
123
123
  w3: "AsyncWeb3"
124
124
 
125
125
  def __call__(self, *args: Any, **kwargs: Any) -> "AsyncContractEvent":
126
- event_abi = get_abi_element(
127
- filter_abi_by_type("event", self.contract_abi),
128
- self.name,
129
- *args,
130
- abi_codec=self.w3.codec,
131
- **kwargs,
132
- )
133
- argument_types = get_abi_input_types(event_abi)
134
- event_signature = str(
135
- get_abi_element_signature(self.abi_element_identifier, argument_types)
136
- )
137
- contract_event = AsyncContractEvent.factory(
138
- event_signature,
139
- w3=self.w3,
140
- contract_abi=self.contract_abi,
141
- address=self.address,
142
- abi_element_identifier=event_signature,
143
- )
144
-
145
- return copy_contract_event(contract_event, *args, **kwargs)
126
+ return copy_contract_event(self, *args, **kwargs)
146
127
 
147
128
  @combomethod
148
129
  async def get_logs(
@@ -297,7 +278,7 @@ class AsyncContractEvents(BaseContractEvents):
297
278
  raise NoABIFound(
298
279
  "There is no ABI found for this contract.",
299
280
  )
300
- if "_events" not in self.__dict__ or len(self._events) == 0:
281
+ elif "_events" not in self.__dict__ or len(self._events) == 0:
301
282
  raise NoABIEventsFound(
302
283
  "The abi for this contract contains no event definitions. ",
303
284
  "Are you sure you provided the correct contract abi?",
@@ -310,11 +291,13 @@ class AsyncContractEvents(BaseContractEvents):
310
291
  f"The event '{event_name}' was not found in this contract's abi. ",
311
292
  "Are you sure you provided the correct contract abi?",
312
293
  )
294
+
295
+ if "(" not in event_name:
296
+ event_name = _get_any_abi_signature_with_name(event_name, self._events)
313
297
  else:
314
- event_abi = get_abi_element(self._events, event_name)
315
- argument_types = get_abi_input_types(event_abi)
316
- event_signature = str(get_abi_element_signature(event_name, argument_types))
317
- return super().__getattribute__(event_signature)
298
+ event_name = f"_{event_name}"
299
+
300
+ return super().__getattribute__(event_name)
318
301
 
319
302
  def __getitem__(self, event_name: str) -> "AsyncContractEvent":
320
303
  return getattr(self, event_name)
@@ -325,39 +308,103 @@ class AsyncContractFunction(BaseContractFunction):
325
308
  w3: "AsyncWeb3"
326
309
 
327
310
  def __call__(self, *args: Any, **kwargs: Any) -> "AsyncContractFunction":
328
- element_name = self.abi_element_identifier
329
- if element_name in ["fallback", "receive"] or len(args) + len(kwargs):
330
- # Use only the name if a fallback, receive function
331
- # or when args/kwargs are present to find the proper element
332
- element_name = self.fn_name
333
-
334
- function_abi = get_abi_element(
335
- filter_by_types(
336
- ["function", "constructor", "fallback", "receive"],
311
+ # When a function is called, check arguments to obtain the correct function
312
+ # in the contract. self will be used if all args and kwargs are
313
+ # encodable to self.abi, otherwise the correct function is obtained from
314
+ # the contract.
315
+ if (
316
+ self.abi_element_identifier in [FallbackFn, ReceiveFn]
317
+ or self.abi_element_identifier == "constructor"
318
+ ):
319
+ return copy_contract_function(self, *args, **kwargs)
320
+
321
+ all_functions = cast(
322
+ List[ABIFunction],
323
+ filter_abi_by_type(
324
+ "function",
337
325
  self.contract_abi,
338
326
  ),
339
- element_name,
340
- *args,
341
- abi_codec=self.w3.codec,
342
- **kwargs,
343
327
  )
344
-
345
- argument_types = None
346
- if function_abi["type"] not in ["fallback", "receive"]:
347
- argument_types = get_abi_input_types(function_abi)
348
-
349
- function_signature = str(
350
- get_abi_element_signature(self.abi_element_identifier, argument_types)
328
+ # Filter functions by name to obtain function signatures
329
+ function_name = get_name_from_abi_element_identifier(
330
+ self.abi_element_identifier
351
331
  )
352
- contract_function = AsyncContractFunction.factory(
353
- function_signature,
354
- w3=self.w3,
355
- contract_abi=self.contract_abi,
356
- address=self.address,
357
- abi_element_identifier=function_signature,
358
- decode_tuples=self.decode_tuples,
332
+ function_abis = [
333
+ function for function in all_functions if function["name"] == function_name
334
+ ]
335
+ num_args = len(args) + len(kwargs)
336
+ function_abis_with_arg_count = cast(
337
+ List[ABIFunction],
338
+ _filter_by_argument_count(
339
+ num_args,
340
+ function_abis,
341
+ ),
359
342
  )
360
343
 
344
+ if not len(function_abis_with_arg_count):
345
+ # Build an ABI without arguments to determine if one exists
346
+ function_abis_with_arg_count = [
347
+ ABIFunction({"type": "function", "name": function_name})
348
+ ]
349
+
350
+ # Check that arguments in call match a function ABI
351
+ num_attempts = 0
352
+ function_abi_matches = []
353
+ contract_function = None
354
+ for abi in function_abis_with_arg_count:
355
+ try:
356
+ num_attempts += 1
357
+
358
+ # Search for a function ABI that matches the arguments used
359
+ function_abi_matches.append(
360
+ cast(
361
+ ABIFunction,
362
+ get_abi_element(
363
+ function_abis,
364
+ abi_to_signature(abi),
365
+ *args,
366
+ abi_codec=self.w3.codec,
367
+ **kwargs,
368
+ ),
369
+ )
370
+ )
371
+ except MismatchedABI:
372
+ # ignore exceptions
373
+ continue
374
+
375
+ if len(function_abi_matches) == 1:
376
+ function_abi = function_abi_matches[0]
377
+ if abi_to_signature(self.abi) == abi_to_signature(function_abi):
378
+ contract_function = self
379
+ else:
380
+ # Found a match that is not self
381
+ contract_function = AsyncContractFunction.factory(
382
+ abi_to_signature(function_abi),
383
+ w3=self.w3,
384
+ contract_abi=self.contract_abi,
385
+ address=self.address,
386
+ abi_element_identifier=abi_to_signature(function_abi),
387
+ abi=function_abi,
388
+ )
389
+ else:
390
+ for abi in function_abi_matches:
391
+ if abi_to_signature(self.abi) == abi_to_signature(abi):
392
+ contract_function = self
393
+ break
394
+ else:
395
+ # Raise exception if multiple found
396
+ raise MismatchedABI(
397
+ _mismatched_abi_error_diagnosis(
398
+ function_name,
399
+ self.contract_abi,
400
+ len(function_abi_matches),
401
+ num_args,
402
+ *args,
403
+ abi_codec=self.w3.codec,
404
+ **kwargs,
405
+ )
406
+ )
407
+
361
408
  return copy_contract_function(contract_function, *args, **kwargs)
362
409
 
363
410
  @classmethod
@@ -536,19 +583,19 @@ class AsyncContractFunctions(BaseContractFunctions):
536
583
  for function in self._functions
537
584
  ]:
538
585
  raise ABIFunctionNotFound(
539
- f"The function '{function_name}' was not found in this contract's "
540
- "abi. Are you sure you provided the correct contract abi?",
586
+ f"The function '{function_name}' was not found in this ",
587
+ "contract's abi.",
541
588
  )
542
589
 
543
- function_identifier = function_name
544
-
545
590
  if "(" not in function_name:
546
- function_identifier = _get_any_abi_signature_with_name(
591
+ function_name = _get_any_abi_signature_with_name(
547
592
  function_name, self._functions
548
593
  )
594
+ else:
595
+ function_name = f"_{function_name}"
549
596
 
550
597
  return super().__getattribute__(
551
- function_identifier,
598
+ function_name,
552
599
  )
553
600
 
554
601
  def __getitem__(self, function_name: str) -> "AsyncContractFunction":
@@ -588,7 +635,11 @@ class AsyncContract(BaseContract):
588
635
  self.abi, self.w3, self.address, decode_tuples=self.decode_tuples
589
636
  )
590
637
  self.caller = AsyncContractCaller(
591
- self.abi, self.w3, self.address, decode_tuples=self.decode_tuples
638
+ self.abi,
639
+ self.w3,
640
+ self.address,
641
+ decode_tuples=self.decode_tuples,
642
+ contract_functions=self.functions,
592
643
  )
593
644
  self.events = AsyncContractEvents(self.abi, self.w3, self.address)
594
645
  self.fallback = AsyncContract.get_fallback_function(
@@ -638,6 +689,7 @@ class AsyncContract(BaseContract):
638
689
  contract.w3,
639
690
  contract.address,
640
691
  decode_tuples=contract.decode_tuples,
692
+ contract_functions=contract.functions,
641
693
  )
642
694
  contract.events = AsyncContractEvents(contract.abi, contract.w3)
643
695
  contract.fallback = AsyncContract.get_fallback_function(
@@ -720,6 +772,7 @@ class AsyncContractCaller(BaseContractCaller):
720
772
  block_identifier: BlockIdentifier = None,
721
773
  ccip_read_enabled: Optional[bool] = None,
722
774
  decode_tuples: Optional[bool] = False,
775
+ contract_functions: Optional[AsyncContractFunctions] = None,
723
776
  ) -> None:
724
777
  super().__init__(abi, w3, address, decode_tuples=decode_tuples)
725
778
 
@@ -727,18 +780,13 @@ class AsyncContractCaller(BaseContractCaller):
727
780
  if transaction is None:
728
781
  transaction = {}
729
782
 
730
- self._functions = get_all_function_abis(self.abi)
731
-
732
- for func in self._functions:
733
- abi_signature = abi_to_signature(func)
734
- fn = AsyncContractFunction.factory(
735
- abi_signature,
736
- w3=w3,
737
- contract_abi=self.abi,
738
- address=self.address,
739
- decode_tuples=decode_tuples,
783
+ if contract_functions is None:
784
+ contract_functions = AsyncContractFunctions(
785
+ abi, w3, address, decode_tuples=decode_tuples
740
786
  )
741
787
 
788
+ self._functions = contract_functions._functions
789
+ for fn in contract_functions.__iter__():
742
790
  caller_method = partial(
743
791
  self.call_function,
744
792
  fn,
@@ -746,8 +794,7 @@ class AsyncContractCaller(BaseContractCaller):
746
794
  block_identifier=block_identifier,
747
795
  ccip_read_enabled=ccip_read_enabled,
748
796
  )
749
-
750
- setattr(self, abi_signature, caller_method)
797
+ setattr(self, str(fn.abi_element_identifier), caller_method)
751
798
 
752
799
  def __call__(
753
800
  self,
@@ -48,7 +48,6 @@ from hexbytes import (
48
48
 
49
49
  from web3._utils.abi import (
50
50
  fallback_func_abi_exists,
51
- filter_by_types,
52
51
  find_constructor_abi_element_by_type,
53
52
  get_abi_element_signature,
54
53
  get_name_from_abi_element_identifier,
@@ -155,27 +154,34 @@ class BaseContractEvent:
155
154
 
156
155
  address: ChecksumAddress = None
157
156
  event_name: str = None
157
+ name: str = None
158
158
  abi_element_identifier: ABIElementIdentifier = None
159
+ signature: str = None
159
160
  w3: Union["Web3", "AsyncWeb3"] = None
160
161
  contract_abi: ABI = None
161
162
  abi: ABIEvent = None
162
- argument_types: Tuple[str] = None
163
+ argument_names: Tuple[str, ...] = tuple()
164
+ argument_types: Tuple[str, ...] = tuple()
163
165
  args: Any = None
164
166
  kwargs: Any = None
165
167
 
166
- def __init__(self, *argument_names: Tuple[str]) -> None:
167
- self.event_name = get_name_from_abi_element_identifier(type(self).__name__)
168
+ def __init__(self, *argument_names: str, abi: Optional[ABIEvent] = None) -> None:
168
169
  self.abi_element_identifier = type(self).__name__
169
- abi = self._get_event_abi()
170
- self.name = abi_to_signature(abi)
171
- self.abi = abi
170
+ self.name = get_name_from_abi_element_identifier(self.abi_element_identifier)
171
+ self.event_name = self.name
172
172
 
173
- if argument_names is None:
174
- # https://github.com/python/mypy/issues/6283
175
- self.argument_names = tuple() # type: ignore
176
- else:
173
+ if abi:
174
+ self.abi = abi
175
+
176
+ self.signature = abi_to_signature(self.abi)
177
+
178
+ if argument_names:
177
179
  self.argument_names = argument_names
178
180
 
181
+ event_inputs = self.abi.get("inputs", [])
182
+ self.argument_names = tuple([input.get("name", None) for input in event_inputs])
183
+ self.argument_types = tuple([input["type"] for input in event_inputs])
184
+
179
185
  def __repr__(self) -> str:
180
186
  if self.abi:
181
187
  return f"<Event {abi_to_signature(self.abi)}>"
@@ -461,7 +467,10 @@ class BaseContractEvents:
461
467
  _events: Sequence[ABIEvent] = None
462
468
 
463
469
  if self.abi:
464
- _events = filter_abi_by_type("event", abi)
470
+ _events = sorted(
471
+ filter_abi_by_type("event", self.abi),
472
+ key=lambda evt: (evt["name"], len(evt.get("inputs", []))),
473
+ )
465
474
  for event in _events:
466
475
  abi_signature = abi_to_signature(event)
467
476
  event_factory = contract_event_type.factory(
@@ -469,9 +478,16 @@ class BaseContractEvents:
469
478
  w3=self.w3,
470
479
  contract_abi=self.abi,
471
480
  address=self.address,
472
- event_name=event["name"],
481
+ abi=event,
473
482
  )
474
- setattr(self, abi_signature, event_factory)
483
+
484
+ # Set event name on instance if it does not already exist
485
+ if event["name"] not in self.__dict__:
486
+ setattr(self, event["name"], event_factory)
487
+
488
+ # Set underscore prefixed event signature on instance
489
+ # Handles ambiguity in overloaded contract events
490
+ setattr(self, f"_{abi_signature}", event_factory)
475
491
 
476
492
  if _events:
477
493
  self._events = _events
@@ -494,6 +510,7 @@ class BaseContractFunction:
494
510
  address: ChecksumAddress = None
495
511
  fn_name: str = None
496
512
  name: str = None
513
+ signature: str = None
497
514
  abi_element_identifier: ABIElementIdentifier = None
498
515
  w3: Union["Web3", "AsyncWeb3"] = None
499
516
  contract_abi: ABI = None
@@ -501,6 +518,8 @@ class BaseContractFunction:
501
518
  transaction: TxParams = None
502
519
  arguments: Tuple[Any, ...] = None
503
520
  decode_tuples: Optional[bool] = None
521
+ argument_names: Tuple[str, ...] = tuple()
522
+ argument_types: Tuple[str, ...] = tuple()
504
523
  args: Any = None
505
524
  kwargs: Any = None
506
525
 
@@ -508,18 +527,17 @@ class BaseContractFunction:
508
527
  if not self.abi_element_identifier:
509
528
  self.abi_element_identifier = type(self).__name__
510
529
 
511
- self.fn_name = get_name_from_abi_element_identifier(self.abi_element_identifier)
512
- self.abi = cast(
513
- ABIFunction,
514
- get_abi_element(
515
- filter_by_types(
516
- ["function", "constructor", "fallback", "receive"],
517
- self.contract_abi,
518
- ),
519
- self.abi_element_identifier,
520
- ),
521
- )
522
- self.name = abi_to_signature(self.abi)
530
+ self.name = get_name_from_abi_element_identifier(self.abi_element_identifier)
531
+ self.fn_name = self.name
532
+
533
+ if abi:
534
+ self.abi = abi
535
+
536
+ self.signature = abi_to_signature(self.abi)
537
+
538
+ event_inputs = self.abi.get("inputs", [])
539
+ self.argument_names = tuple([input.get("name", None) for input in event_inputs])
540
+ self.argument_types = tuple([input["type"] for input in event_inputs])
523
541
 
524
542
  @combomethod
525
543
  def _get_abi(cls) -> ABIFunction:
@@ -553,13 +571,9 @@ class BaseContractFunction:
553
571
  FallbackFn,
554
572
  ReceiveFn,
555
573
  ]:
556
- self.abi = self._get_abi()
557
-
558
574
  self.selector = encode_hex(function_abi_to_4byte_selector(self.abi))
559
575
  self.arguments = None
560
576
  elif is_text(self.abi_element_identifier):
561
- self.abi = self._get_abi()
562
-
563
577
  self.selector = encode_hex(function_abi_to_4byte_selector(self.abi))
564
578
  self.arguments = get_normalized_abi_inputs(
565
579
  self.abi, *self.args, **self.kwargs
@@ -727,21 +741,33 @@ class BaseContractFunctions:
727
741
  _functions: Sequence[ABIFunction] = None
728
742
 
729
743
  if self.abi:
730
- _functions = filter_abi_by_type("function", self.abi)
744
+ # Function with least number of inputs is first
745
+ # This ensures ambiguity will always be deterministic
746
+ # Prefer function without arguments if present, otherwise
747
+ # just use the first available
748
+ _functions = sorted(
749
+ filter_abi_by_type("function", self.abi),
750
+ key=lambda fn: (fn["name"], len(fn.get("inputs", []))),
751
+ )
731
752
  for func in _functions:
732
753
  abi_signature = abi_to_signature(func)
733
- setattr(
734
- self,
754
+ function_factory = contract_function_class.factory(
735
755
  abi_signature,
736
- contract_function_class.factory(
737
- abi_signature,
738
- w3=self.w3,
739
- contract_abi=self.abi,
740
- address=self.address,
741
- decode_tuples=decode_tuples,
742
- ),
756
+ w3=self.w3,
757
+ contract_abi=self.abi,
758
+ address=self.address,
759
+ decode_tuples=decode_tuples,
760
+ abi=func,
743
761
  )
744
762
 
763
+ # Set function name on instance if it does not already exist
764
+ if func["name"] not in self.__dict__:
765
+ setattr(self, func["name"], function_factory)
766
+
767
+ # Set function signature on instance
768
+ # Handles ambiguity in overloaded contract functions
769
+ setattr(self, f"_{abi_signature}", function_factory)
770
+
745
771
  if _functions:
746
772
  self._functions = _functions
747
773
 
@@ -1100,12 +1126,14 @@ class BaseContract:
1100
1126
  address: Optional[ChecksumAddress] = None,
1101
1127
  ) -> "BaseContractFunction":
1102
1128
  if abi and fallback_func_abi_exists(abi):
1129
+ fallback_abi = filter_abi_by_type("fallback", abi)[0]
1103
1130
  return function_type.factory(
1104
1131
  "fallback",
1105
1132
  w3=w3,
1106
1133
  contract_abi=abi,
1107
1134
  address=address,
1108
1135
  abi_element_identifier=FallbackFn,
1136
+ abi=fallback_abi,
1109
1137
  )()
1110
1138
 
1111
1139
  return cast(function_type, NonExistentFallbackFunction()) # type: ignore
@@ -1118,12 +1146,14 @@ class BaseContract:
1118
1146
  address: Optional[ChecksumAddress] = None,
1119
1147
  ) -> "BaseContractFunction":
1120
1148
  if abi and receive_func_abi_exists(abi):
1149
+ receive_abi = filter_abi_by_type("receive", abi)[0]
1121
1150
  return function_type.factory(
1122
1151
  "receive",
1123
1152
  w3=w3,
1124
1153
  contract_abi=abi,
1125
1154
  address=address,
1126
1155
  abi_element_identifier=ReceiveFn,
1156
+ abi=receive_abi,
1127
1157
  )()
1128
1158
 
1129
1159
  return cast(function_type, NonExistentReceiveFunction()) # type: ignore