slither.core.declarations.contract

" Contract module

   1""""
   2    Contract module
   3"""
   4import logging
   5from collections import defaultdict
   6from pathlib import Path
   7from typing import Optional, List, Dict, Callable, Tuple, TYPE_CHECKING, Union, Set, Any
   8
   9from crytic_compile.platform import Type as PlatformType
  10
  11from slither.core.cfg.scope import Scope
  12from slither.core.source_mapping.source_mapping import SourceMapping
  13from slither.utils.using_for import USING_FOR, merge_using_for
  14from slither.core.declarations.function import Function, FunctionType, FunctionLanguage
  15from slither.utils.erc import (
  16    ERC20_signatures,
  17    ERC165_signatures,
  18    ERC223_signatures,
  19    ERC721_signatures,
  20    ERC1820_signatures,
  21    ERC777_signatures,
  22    ERC1155_signatures,
  23    ERC2612_signatures,
  24    ERC1363_signatures,
  25    ERC4524_signatures,
  26    ERC4626_signatures,
  27)
  28from slither.utils.tests_pattern import is_test_contract
  29
  30# pylint: disable=too-many-lines,too-many-instance-attributes,import-outside-toplevel,too-many-nested-blocks
  31if TYPE_CHECKING:
  32    from slither.utils.type_helpers import LibraryCallType, HighLevelCallType, InternalCallType
  33    from slither.core.declarations import (
  34        Enum,
  35        EventContract,
  36        Modifier,
  37        EnumContract,
  38        StructureContract,
  39        FunctionContract,
  40        CustomErrorContract,
  41    )
  42    from slither.slithir.variables.variable import SlithIRVariable
  43    from slither.core.variables import Variable, StateVariable
  44    from slither.core.compilation_unit import SlitherCompilationUnit
  45    from slither.core.scope.scope import FileScope
  46    from slither.core.cfg.node import Node
  47    from slither.core.solidity_types import TypeAliasContract
  48
  49
  50LOGGER = logging.getLogger("Contract")
  51
  52
  53class Contract(SourceMapping):  # pylint: disable=too-many-public-methods
  54    """
  55    Contract class
  56    """
  57
  58    def __init__(self, compilation_unit: "SlitherCompilationUnit", scope: "FileScope") -> None:
  59        super().__init__()
  60
  61        self._name: Optional[str] = None
  62        self._id: Optional[int] = None
  63        self._inheritance: List["Contract"] = []  # all contract inherited, c3 linearization
  64        self._immediate_inheritance: List["Contract"] = []  # immediate inheritance
  65
  66        # Constructors called on contract's definition
  67        # contract B is A(1) { ..
  68        self._explicit_base_constructor_calls: List["Contract"] = []
  69
  70        self._enums: Dict[str, "EnumContract"] = {}
  71        self._structures: Dict[str, "StructureContract"] = {}
  72        self._events: Dict[str, "EventContract"] = {}
  73        # map accessible variable from name -> variable
  74        # do not contain private variables inherited from contract
  75        self._variables: Dict[str, "StateVariable"] = {}
  76        self._variables_ordered: List["StateVariable"] = []
  77        # Reference id -> variable declaration (only available for compact AST)
  78        self._state_variables_by_ref_id: Dict[int, "StateVariable"] = {}
  79        self._modifiers: Dict[str, "Modifier"] = {}
  80        self._functions: Dict[str, "FunctionContract"] = {}
  81        self._linearizedBaseContracts: List[int] = []
  82        self._custom_errors: Dict[str, "CustomErrorContract"] = {}
  83        self._type_aliases: Dict[str, "TypeAliasContract"] = {}
  84
  85        # The only str is "*"
  86        self._using_for: USING_FOR = {}
  87        self._using_for_complete: Optional[USING_FOR] = None
  88        self._kind: Optional[str] = None
  89        self._is_interface: bool = False
  90        self._is_library: bool = False
  91        self._is_fully_implemented: bool = False
  92        self._is_abstract: bool = False
  93
  94        self._signatures: Optional[List[str]] = None
  95        self._signatures_declared: Optional[List[str]] = None
  96
  97        self._fallback_function: Optional["FunctionContract"] = None
  98        self._receive_function: Optional["FunctionContract"] = None
  99
 100        self._is_upgradeable: Optional[bool] = None
 101        self._is_upgradeable_proxy: Optional[bool] = None
 102        self._upgradeable_version: Optional[str] = None
 103
 104        self._initial_state_variables: List["StateVariable"] = []  # ssa
 105
 106        self._is_incorrectly_parsed: bool = False
 107
 108        self._available_functions_as_dict: Optional[Dict[str, "Function"]] = None
 109        self._all_functions_called: Optional[List["InternalCallType"]] = None
 110
 111        self.compilation_unit: "SlitherCompilationUnit" = compilation_unit
 112        self.file_scope: "FileScope" = scope
 113
 114        # memoize
 115        self._state_variables_used_in_reentrant_targets: Optional[
 116            Dict["StateVariable", Set[Union["StateVariable", "Function"]]]
 117        ] = None
 118
 119        self._comments: Optional[str] = None
 120
 121    ###################################################################################
 122    ###################################################################################
 123    # region General's properties
 124    ###################################################################################
 125    ###################################################################################
 126
 127    @property
 128    def name(self) -> str:
 129        """str: Name of the contract."""
 130        assert self._name
 131        return self._name
 132
 133    @name.setter
 134    def name(self, name: str) -> None:
 135        self._name = name
 136
 137    @property
 138    def id(self) -> int:
 139        """Unique id."""
 140        assert self._id is not None
 141        return self._id
 142
 143    @id.setter
 144    def id(self, new_id: int) -> None:
 145        """Unique id."""
 146        self._id = new_id
 147
 148    @property
 149    def contract_kind(self) -> Optional[str]:
 150        """
 151        contract_kind can be None if the legacy ast format is used
 152        :return:
 153        """
 154        return self._kind
 155
 156    @contract_kind.setter
 157    def contract_kind(self, kind: str) -> None:
 158        self._kind = kind
 159
 160    @property
 161    def is_interface(self) -> bool:
 162        return self._is_interface
 163
 164    @is_interface.setter
 165    def is_interface(self, is_interface: bool) -> None:
 166        self._is_interface = is_interface
 167
 168    @property
 169    def is_library(self) -> bool:
 170        return self._is_library
 171
 172    @is_library.setter
 173    def is_library(self, is_library: bool) -> None:
 174        self._is_library = is_library
 175
 176    @property
 177    def comments(self) -> Optional[str]:
 178        """
 179        Return the comments associated with the contract.
 180
 181        When using comments, avoid strict text matching, as the solc behavior might change.
 182        For example, for old solc version, the first space after the * is not kept, i.e:
 183
 184          * @title Test Contract
 185          * @dev Test comment
 186
 187        Returns
 188        - " @title Test Contract\n @dev Test comment" for newest versions
 189        - "@title Test Contract\n@dev Test comment" for older versions
 190
 191
 192        Returns:
 193            the comment as a string
 194        """
 195        return self._comments
 196
 197    @comments.setter
 198    def comments(self, comments: str):
 199        self._comments = comments
 200
 201    @property
 202    def is_fully_implemented(self) -> bool:
 203        """
 204        bool: True if the contract defines all functions.
 205        In modern Solidity, virtual functions can lack an implementation.
 206        Prior to Solidity 0.6.0, functions like the following would be not fully implemented:
 207        ```solidity
 208        contract ImplicitAbstract{
 209            function f() public;
 210        }
 211        ```
 212        """
 213        return self._is_fully_implemented
 214
 215    @is_fully_implemented.setter
 216    def is_fully_implemented(self, is_fully_implemented: bool):
 217        self._is_fully_implemented = is_fully_implemented
 218
 219    @property
 220    def is_abstract(self) -> bool:
 221        """
 222        Note for Solidity < 0.6.0 it will always be false
 223        bool: True if the contract is abstract.
 224        """
 225        return self._is_abstract
 226
 227    @is_abstract.setter
 228    def is_abstract(self, is_abstract: bool):
 229        self._is_abstract = is_abstract
 230
 231    # endregion
 232    ###################################################################################
 233    ###################################################################################
 234    # region Structures
 235    ###################################################################################
 236    ###################################################################################
 237
 238    @property
 239    def structures(self) -> List["StructureContract"]:
 240        """
 241        list(Structure): List of the structures
 242        """
 243        return list(self._structures.values())
 244
 245    @property
 246    def structures_inherited(self) -> List["StructureContract"]:
 247        """
 248        list(Structure): List of the inherited structures
 249        """
 250        return [s for s in self.structures if s.contract != self]
 251
 252    @property
 253    def structures_declared(self) -> List["StructureContract"]:
 254        """
 255        list(Structues): List of the structures declared within the contract (not inherited)
 256        """
 257        return [s for s in self.structures if s.contract == self]
 258
 259    @property
 260    def structures_as_dict(self) -> Dict[str, "StructureContract"]:
 261        return self._structures
 262
 263    # endregion
 264    ###################################################################################
 265    ###################################################################################
 266    # region Enums
 267    ###################################################################################
 268    ###################################################################################
 269
 270    @property
 271    def enums(self) -> List["EnumContract"]:
 272        return list(self._enums.values())
 273
 274    @property
 275    def enums_inherited(self) -> List["EnumContract"]:
 276        """
 277        list(Enum): List of the inherited enums
 278        """
 279        return [e for e in self.enums if e.contract != self]
 280
 281    @property
 282    def enums_declared(self) -> List["EnumContract"]:
 283        """
 284        list(Enum): List of the enums declared within the contract (not inherited)
 285        """
 286        return [e for e in self.enums if e.contract == self]
 287
 288    @property
 289    def enums_as_dict(self) -> Dict[str, "EnumContract"]:
 290        return self._enums
 291
 292    # endregion
 293    ###################################################################################
 294    ###################################################################################
 295    # region Events
 296    ###################################################################################
 297    ###################################################################################
 298
 299    @property
 300    def events(self) -> List["EventContract"]:
 301        """
 302        list(Event): List of the events
 303        """
 304        return list(self._events.values())
 305
 306    @property
 307    def events_inherited(self) -> List["EventContract"]:
 308        """
 309        list(Event): List of the inherited events
 310        """
 311        return [e for e in self.events if e.contract != self]
 312
 313    @property
 314    def events_declared(self) -> List["EventContract"]:
 315        """
 316        list(Event): List of the events declared within the contract (not inherited)
 317        """
 318        return [e for e in self.events if e.contract == self]
 319
 320    @property
 321    def events_as_dict(self) -> Dict[str, "EventContract"]:
 322        return self._events
 323
 324    # endregion
 325    ###################################################################################
 326    ###################################################################################
 327    # region Using for
 328    ###################################################################################
 329    ###################################################################################
 330
 331    @property
 332    def using_for(self) -> USING_FOR:
 333        return self._using_for
 334
 335    @property
 336    def using_for_complete(self) -> USING_FOR:
 337        """
 338        USING_FOR: Dict of merged local using for directive with top level directive
 339        """
 340
 341        if self._using_for_complete is None:
 342            result = self.using_for
 343            top_level_using_for = self.file_scope.using_for_directives
 344            for uftl in top_level_using_for:
 345                result = merge_using_for(result, uftl.using_for)
 346            self._using_for_complete = result
 347        return self._using_for_complete
 348
 349    # endregion
 350    ###################################################################################
 351    ###################################################################################
 352    # region Custom Errors
 353    ###################################################################################
 354    ###################################################################################
 355
 356    @property
 357    def custom_errors(self) -> List["CustomErrorContract"]:
 358        """
 359        list(CustomErrorContract): List of the contract's custom errors
 360        """
 361        return list(self._custom_errors.values())
 362
 363    @property
 364    def custom_errors_inherited(self) -> List["CustomErrorContract"]:
 365        """
 366        list(CustomErrorContract): List of the inherited custom errors
 367        """
 368        return [s for s in self.custom_errors if s.contract != self]
 369
 370    @property
 371    def custom_errors_declared(self) -> List["CustomErrorContract"]:
 372        """
 373        list(CustomErrorContract): List of the custom errors declared within the contract (not inherited)
 374        """
 375        return [s for s in self.custom_errors if s.contract == self]
 376
 377    @property
 378    def custom_errors_as_dict(self) -> Dict[str, "CustomErrorContract"]:
 379        return self._custom_errors
 380
 381    # endregion
 382    ###################################################################################
 383    ###################################################################################
 384    # region Custom Errors
 385    ###################################################################################
 386    ###################################################################################
 387
 388    @property
 389    def type_aliases(self) -> List["TypeAliasContract"]:
 390        """
 391        list(TypeAliasContract): List of the contract's custom errors
 392        """
 393        return list(self._type_aliases.values())
 394
 395    @property
 396    def type_aliases_inherited(self) -> List["TypeAliasContract"]:
 397        """
 398        list(TypeAliasContract): List of the inherited custom errors
 399        """
 400        return [s for s in self.type_aliases if s.contract != self]
 401
 402    @property
 403    def type_aliases_declared(self) -> List["TypeAliasContract"]:
 404        """
 405        list(TypeAliasContract): List of the custom errors declared within the contract (not inherited)
 406        """
 407        return [s for s in self.type_aliases if s.contract == self]
 408
 409    @property
 410    def type_aliases_as_dict(self) -> Dict[str, "TypeAliasContract"]:
 411        return self._type_aliases
 412
 413    # endregion
 414    ###################################################################################
 415    ###################################################################################
 416    # region Variables
 417    ###################################################################################
 418    ###################################################################################
 419    @property
 420    def state_variables_by_ref_id(self) -> Dict[int, "StateVariable"]:
 421        """
 422        Returns the state variables by reference id (only available for compact AST).
 423        """
 424        return self._state_variables_by_ref_id
 425
 426    @property
 427    def variables(self) -> List["StateVariable"]:
 428        """
 429        Returns all the accessible variables (do not include private variable from inherited contract)
 430
 431        list(StateVariable): List of the state variables. Alias to self.state_variables.
 432        """
 433        return list(self.state_variables)
 434
 435    @property
 436    def variables_as_dict(self) -> Dict[str, "StateVariable"]:
 437        return self._variables
 438
 439    @property
 440    def state_variables(self) -> List["StateVariable"]:
 441        """
 442        Returns all the accessible variables (do not include private variable from inherited contract).
 443        Use state_variables_ordered for all the variables following the storage order
 444
 445        list(StateVariable): List of the state variables.
 446        """
 447        return list(self._variables.values())
 448
 449    @property
 450    def stored_state_variables(self) -> List["StateVariable"]:
 451        """
 452        Returns state variables with storage locations, excluding private variables from inherited contracts.
 453        Use stored_state_variables_ordered to access variables with storage locations in their declaration order.
 454
 455        This implementation filters out state variables if they are constant or immutable. It will be
 456        updated to accommodate any new non-storage keywords that might replace 'constant' and 'immutable' in the future.
 457
 458        Returns:
 459            List[StateVariable]: A list of state variables with storage locations.
 460        """
 461        return [variable for variable in self.state_variables if variable.is_stored]
 462
 463    @property
 464    def stored_state_variables_ordered(self) -> List["StateVariable"]:
 465        """
 466        list(StateVariable): List of the state variables with storage locations by order of declaration.
 467
 468        This implementation filters out state variables if they are constant or immutable. It will be
 469        updated to accommodate any new non-storage keywords that might replace 'constant' and 'immutable' in the future.
 470
 471        Returns:
 472            List[StateVariable]: A list of state variables with storage locations ordered by declaration.
 473        """
 474        return [variable for variable in self.state_variables_ordered if variable.is_stored]
 475
 476    @property
 477    def state_variables_entry_points(self) -> List["StateVariable"]:
 478        """
 479        list(StateVariable): List of the state variables that are public.
 480        """
 481        return [var for var in self._variables.values() if var.visibility == "public"]
 482
 483    @property
 484    def state_variables_ordered(self) -> List["StateVariable"]:
 485        """
 486        list(StateVariable): List of the state variables by order of declaration.
 487        """
 488        return list(self._variables_ordered)
 489
 490    def add_variables_ordered(self, new_vars: List["StateVariable"]) -> None:
 491        self._variables_ordered += new_vars
 492
 493    @property
 494    def state_variables_inherited(self) -> List["StateVariable"]:
 495        """
 496        list(StateVariable): List of the inherited state variables
 497        """
 498        return [s for s in self.state_variables if s.contract != self]
 499
 500    @property
 501    def state_variables_declared(self) -> List["StateVariable"]:
 502        """
 503        list(StateVariable): List of the state variables declared within the contract (not inherited)
 504        """
 505        return [s for s in self.state_variables if s.contract == self]
 506
 507    @property
 508    def slithir_variables(self) -> List["SlithIRVariable"]:
 509        """
 510        List all of the slithir variables (non SSA)
 511        """
 512        slithir_variabless = [f.slithir_variables for f in self.functions + self.modifiers]  # type: ignore
 513        slithir_variables = [item for sublist in slithir_variabless for item in sublist]
 514        return list(set(slithir_variables))
 515
 516    @property
 517    def state_variables_used_in_reentrant_targets(
 518        self,
 519    ) -> Dict["StateVariable", Set[Union["StateVariable", "Function"]]]:
 520        """
 521        Returns the state variables used in reentrant targets. Heuristics:
 522        - Variable used (read/write) in entry points that are reentrant
 523        - State variables that are public
 524
 525        """
 526        from slither.core.variables.state_variable import StateVariable
 527
 528        if self._state_variables_used_in_reentrant_targets is None:
 529            reentrant_functions = [f for f in self.functions_entry_points if f.is_reentrant]
 530            variables_used: Dict[
 531                StateVariable, Set[Union[StateVariable, "Function"]]
 532            ] = defaultdict(set)
 533            for function in reentrant_functions:
 534                for ir in function.all_slithir_operations():
 535                    state_variables = [v for v in ir.used if isinstance(v, StateVariable)]
 536                    for state_variable in state_variables:
 537                        variables_used[state_variable].add(ir.node.function)
 538            for variable in [v for v in self.state_variables if v.visibility == "public"]:
 539                variables_used[variable].add(variable)
 540            self._state_variables_used_in_reentrant_targets = variables_used
 541        return self._state_variables_used_in_reentrant_targets
 542
 543    # endregion
 544    ###################################################################################
 545    ###################################################################################
 546    # region Constructors
 547    ###################################################################################
 548    ###################################################################################
 549
 550    @property
 551    def constructor(self) -> Optional["Function"]:
 552        """
 553        Return the contract's immediate constructor.
 554        If there is no immediate constructor, returns the first constructor
 555        executed, following the c3 linearization
 556        Return None if there is no constructor.
 557        """
 558        cst = self.constructors_declared
 559        if cst:
 560            return cst
 561        for inherited_contract in self.inheritance:
 562            cst = inherited_contract.constructors_declared
 563            if cst:
 564                return cst
 565        return None
 566
 567    @property
 568    def constructors_declared(self) -> Optional["Function"]:
 569        return next(
 570            (
 571                func
 572                for func in self.functions
 573                if func.is_constructor and func.contract_declarer == self
 574            ),
 575            None,
 576        )
 577
 578    @property
 579    def constructors(self) -> List["FunctionContract"]:
 580        """
 581        Return the list of constructors (including inherited)
 582        """
 583        return [func for func in self.functions if func.is_constructor]
 584
 585    @property
 586    def explicit_base_constructor_calls(self) -> List["Function"]:
 587        """
 588        list(Function): List of the base constructors called explicitly by this contract definition.
 589
 590                        Base constructors called by any constructor definition will not be included.
 591                        Base constructors implicitly called by the contract definition (without
 592                        parenthesis) will not be included.
 593
 594                        On "contract B is A(){..}" it returns the constructor of A
 595        """
 596        return [c.constructor for c in self._explicit_base_constructor_calls if c.constructor]
 597
 598    # endregion
 599    ###################################################################################
 600    ###################################################################################
 601    # region Functions and Modifiers
 602    ###################################################################################
 603    ###################################################################################
 604
 605    @property
 606    def functions_signatures(self) -> List[str]:
 607        """
 608        Return the signatures of all the public/eterxnal functions/state variables
 609        :return: list(string) the signatures of all the functions that can be called
 610        """
 611        if self._signatures is None:
 612            sigs = [
 613                v.full_name for v in self.state_variables if v.visibility in ["public", "external"]
 614            ]
 615
 616            sigs += {f.full_name for f in self.functions if f.visibility in ["public", "external"]}
 617            self._signatures = list(set(sigs))
 618        return self._signatures
 619
 620    @property
 621    def functions_signatures_declared(self) -> List[str]:
 622        """
 623        Return the signatures of the public/eterxnal functions/state variables that are declared by this contract
 624        :return: list(string) the signatures of all the functions that can be called and are declared by this contract
 625        """
 626        if self._signatures_declared is None:
 627            sigs = [
 628                v.full_name
 629                for v in self.state_variables_declared
 630                if v.visibility in ["public", "external"]
 631            ]
 632
 633            sigs += {
 634                f.full_name
 635                for f in self.functions_declared
 636                if f.visibility in ["public", "external"]
 637            }
 638            self._signatures_declared = list(set(sigs))
 639        return self._signatures_declared
 640
 641    @property
 642    def functions(self) -> List["FunctionContract"]:
 643        """
 644        list(Function): List of the functions
 645        """
 646        return list(self._functions.values())
 647
 648    def available_functions_as_dict(self) -> Dict[str, "Function"]:
 649        if self._available_functions_as_dict is None:
 650            self._available_functions_as_dict = {
 651                f.full_name: f for f in self._functions.values() if not f.is_shadowed
 652            }
 653        return self._available_functions_as_dict
 654
 655    def add_function(self, func: "FunctionContract") -> None:
 656        self._functions[func.canonical_name] = func
 657
 658    def set_functions(self, functions: Dict[str, "FunctionContract"]) -> None:
 659        """
 660        Set the functions
 661
 662        :param functions:  dict full_name -> function
 663        :return:
 664        """
 665        self._functions = functions
 666
 667    @property
 668    def functions_inherited(self) -> List["FunctionContract"]:
 669        """
 670        list(Function): List of the inherited functions
 671        """
 672        return [f for f in self.functions if f.contract_declarer != self]
 673
 674    @property
 675    def functions_declared(self) -> List["FunctionContract"]:
 676        """
 677        list(Function): List of the functions defined within the contract (not inherited)
 678        """
 679        return [f for f in self.functions if f.contract_declarer == self]
 680
 681    @property
 682    def functions_entry_points(self) -> List["FunctionContract"]:
 683        """
 684        list(Functions): List of public and external functions
 685        """
 686        return [
 687            f
 688            for f in self.functions
 689            if f.visibility in ["public", "external"] and not f.is_shadowed or f.is_fallback
 690        ]
 691
 692    @property
 693    def modifiers(self) -> List["Modifier"]:
 694        """
 695        list(Modifier): List of the modifiers
 696        """
 697        return list(self._modifiers.values())
 698
 699    def available_modifiers_as_dict(self) -> Dict[str, "Modifier"]:
 700        return {m.full_name: m for m in self._modifiers.values() if not m.is_shadowed}
 701
 702    def set_modifiers(self, modifiers: Dict[str, "Modifier"]) -> None:
 703        """
 704        Set the modifiers
 705
 706        :param modifiers:  dict full_name -> modifier
 707        :return:
 708        """
 709        self._modifiers = modifiers
 710
 711    @property
 712    def modifiers_inherited(self) -> List["Modifier"]:
 713        """
 714        list(Modifier): List of the inherited modifiers
 715        """
 716        return [m for m in self.modifiers if m.contract_declarer != self]
 717
 718    @property
 719    def modifiers_declared(self) -> List["Modifier"]:
 720        """
 721        list(Modifier): List of the modifiers defined within the contract (not inherited)
 722        """
 723        return [m for m in self.modifiers if m.contract_declarer == self]
 724
 725    @property
 726    def functions_and_modifiers(self) -> List["Function"]:
 727        """
 728        list(Function|Modifier): List of the functions and modifiers
 729        """
 730        return self.functions + self.modifiers  # type: ignore
 731
 732    @property
 733    def functions_and_modifiers_inherited(self) -> List["Function"]:
 734        """
 735        list(Function|Modifier): List of the inherited functions and modifiers
 736        """
 737        return self.functions_inherited + self.modifiers_inherited  # type: ignore
 738
 739    @property
 740    def functions_and_modifiers_declared(self) -> List["Function"]:
 741        """
 742        list(Function|Modifier): List of the functions and modifiers defined within the contract (not inherited)
 743        """
 744        return self.functions_declared + self.modifiers_declared  # type: ignore
 745
 746    @property
 747    def fallback_function(self) -> Optional["FunctionContract"]:
 748        if self._fallback_function is None:
 749            for f in self.functions:
 750                if f.is_fallback:
 751                    self._fallback_function = f
 752                    break
 753        return self._fallback_function
 754
 755    @property
 756    def receive_function(self) -> Optional["FunctionContract"]:
 757        if self._receive_function is None:
 758            for f in self.functions:
 759                if f.is_receive:
 760                    self._receive_function = f
 761                    break
 762        return self._receive_function
 763
 764    def available_elements_from_inheritances(
 765        self,
 766        elements: Dict[str, "Function"],
 767        getter_available: Callable[["Contract"], List["FunctionContract"]],
 768    ) -> Dict[str, "Function"]:
 769        """
 770
 771        :param elements: dict(canonical_name -> elements)
 772        :param getter_available: fun x
 773        :return:
 774        """
 775        # keep track of the contracts visited
 776        # to prevent an ovveride due to multiple inheritance of the same contract
 777        # A is B, C, D is C, --> the second C was already seen
 778        inherited_elements: Dict[str, "FunctionContract"] = {}
 779        accessible_elements = {}
 780        contracts_visited = []
 781        for father in self.inheritance_reverse:
 782            functions: Dict[str, "FunctionContract"] = {
 783                v.full_name: v
 784                for v in getter_available(father)
 785                if v.contract not in contracts_visited
 786                and v.function_language
 787                != FunctionLanguage.Yul  # Yul functions are not propagated in the inheritance
 788            }
 789            contracts_visited.append(father)
 790            inherited_elements.update(functions)
 791
 792        for element in inherited_elements.values():
 793            accessible_elements[element.full_name] = elements[element.canonical_name]
 794
 795        return accessible_elements
 796
 797    # endregion
 798    ###################################################################################
 799    ###################################################################################
 800    # region Inheritance
 801    ###################################################################################
 802    ###################################################################################
 803
 804    @property
 805    def inheritance(self) -> List["Contract"]:
 806        """
 807        list(Contract): Inheritance list. Order: the first elem is the first father to be executed
 808        """
 809        return list(self._inheritance)
 810
 811    @property
 812    def immediate_inheritance(self) -> List["Contract"]:
 813        """
 814        list(Contract): List of contracts immediately inherited from (fathers). Order: order of declaration.
 815        """
 816        return list(self._immediate_inheritance)
 817
 818    @property
 819    def inheritance_reverse(self) -> List["Contract"]:
 820        """
 821        list(Contract): Inheritance list. Order: the last elem is the first father to be executed
 822        """
 823        return list(reversed(self._inheritance))
 824
 825    def set_inheritance(
 826        self,
 827        inheritance: List["Contract"],
 828        immediate_inheritance: List["Contract"],
 829        called_base_constructor_contracts: List["Contract"],
 830    ) -> None:
 831        self._inheritance = inheritance
 832        self._immediate_inheritance = immediate_inheritance
 833        self._explicit_base_constructor_calls = called_base_constructor_contracts
 834
 835    @property
 836    def derived_contracts(self) -> List["Contract"]:
 837        """
 838        list(Contract): Return the list of contracts derived from self
 839        """
 840        candidates = self.compilation_unit.contracts
 841        return [c for c in candidates if self in c.inheritance]  # type: ignore
 842
 843    # endregion
 844    ###################################################################################
 845    ###################################################################################
 846    # region Getters from/to object
 847    ###################################################################################
 848    ###################################################################################
 849
 850    def get_functions_reading_from_variable(self, variable: "Variable") -> List["Function"]:
 851        """
 852        Return the functions reading the variable
 853        """
 854        return [f for f in self.functions if f.is_reading(variable)]
 855
 856    def get_functions_writing_to_variable(self, variable: "Variable") -> List["Function"]:
 857        """
 858        Return the functions writting the variable
 859        """
 860        return [f for f in self.functions if f.is_writing(variable)]
 861
 862    def get_function_from_full_name(self, full_name: str) -> Optional["Function"]:
 863        """
 864            Return a function from a full name
 865            The full name differs from the solidity's signature are the type are conserved
 866            For example contract type are kept, structure are not unrolled, etc
 867        Args:
 868            full_name (str): signature of the function (without return statement)
 869        Returns:
 870            Function
 871        """
 872        return next(
 873            (f for f in self.functions if f.full_name == full_name and not f.is_shadowed),
 874            None,
 875        )
 876
 877    def get_function_from_signature(self, function_signature: str) -> Optional["Function"]:
 878        """
 879            Return a function from a signature
 880        Args:
 881            function_signature (str): signature of the function (without return statement)
 882        Returns:
 883            Function
 884        """
 885        return next(
 886            (
 887                f
 888                for f in self.functions
 889                if f.solidity_signature == function_signature and not f.is_shadowed
 890            ),
 891            None,
 892        )
 893
 894    def get_modifier_from_signature(self, modifier_signature: str) -> Optional["Modifier"]:
 895        """
 896        Return a modifier from a signature
 897
 898        :param modifier_signature:
 899        """
 900        return next(
 901            (m for m in self.modifiers if m.full_name == modifier_signature and not m.is_shadowed),
 902            None,
 903        )
 904
 905    def get_function_from_canonical_name(self, canonical_name: str) -> Optional["Function"]:
 906        """
 907            Return a function from a canonical name (contract.signature())
 908        Args:
 909            canonical_name (str): canonical name of the function (without return statement)
 910        Returns:
 911            Function
 912        """
 913        return next((f for f in self.functions if f.canonical_name == canonical_name), None)
 914
 915    def get_modifier_from_canonical_name(self, canonical_name: str) -> Optional["Modifier"]:
 916        """
 917            Return a modifier from a canonical name (contract.signature())
 918        Args:
 919            canonical_name (str): canonical name of the modifier
 920        Returns:
 921            Modifier
 922        """
 923        return next((m for m in self.modifiers if m.canonical_name == canonical_name), None)
 924
 925    def get_state_variable_from_name(self, variable_name: str) -> Optional["StateVariable"]:
 926        """
 927        Return a state variable from a name
 928
 929        :param variable_name:
 930        """
 931        return next((v for v in self.state_variables if v.name == variable_name), None)
 932
 933    def get_state_variable_from_canonical_name(
 934        self, canonical_name: str
 935    ) -> Optional["StateVariable"]:
 936        """
 937            Return a state variable from a canonical_name
 938        Args:
 939            canonical_name (str): name of the variable
 940        Returns:
 941            StateVariable
 942        """
 943        return next((v for v in self.state_variables if v.canonical_name == canonical_name), None)
 944
 945    def get_structure_from_name(self, structure_name: str) -> Optional["StructureContract"]:
 946        """
 947            Return a structure from a name
 948        Args:
 949            structure_name (str): name of the structure
 950        Returns:
 951            StructureContract
 952        """
 953        return next((st for st in self.structures if st.name == structure_name), None)
 954
 955    def get_structure_from_canonical_name(
 956        self, structure_name: str
 957    ) -> Optional["StructureContract"]:
 958        """
 959            Return a structure from a canonical name
 960        Args:
 961            structure_name (str): canonical name of the structure
 962        Returns:
 963            StructureContract
 964        """
 965        return next((st for st in self.structures if st.canonical_name == structure_name), None)
 966
 967    def get_event_from_signature(self, event_signature: str) -> Optional["Event"]:
 968        """
 969            Return an event from a signature
 970        Args:
 971            event_signature (str): signature of the event
 972        Returns:
 973            Event
 974        """
 975        return next((e for e in self.events if e.full_name == event_signature), None)
 976
 977    def get_event_from_canonical_name(self, event_canonical_name: str) -> Optional["Event"]:
 978        """
 979            Return an event from a canonical name
 980        Args:
 981            event_canonical_name (str): name of the event
 982        Returns:
 983            Event
 984        """
 985        return next((e for e in self.events if e.canonical_name == event_canonical_name), None)
 986
 987    def get_enum_from_name(self, enum_name: str) -> Optional["Enum"]:
 988        """
 989            Return an enum from a name
 990        Args:
 991            enum_name (str): name of the enum
 992        Returns:
 993            Enum
 994        """
 995        return next((e for e in self.enums if e.name == enum_name), None)
 996
 997    def get_enum_from_canonical_name(self, enum_name: str) -> Optional["Enum"]:
 998        """
 999            Return an enum from a canonical name
1000        Args:
1001            enum_name (str): canonical name of the enum
1002        Returns:
1003            Enum
1004        """
1005        return next((e for e in self.enums if e.canonical_name == enum_name), None)
1006
1007    def get_functions_overridden_by(self, function: "Function") -> List["Function"]:
1008        """
1009            Return the list of functions overridden by the function
1010        Args:
1011            (core.Function)
1012        Returns:
1013            list(core.Function)
1014
1015        """
1016        return function.overrides
1017
1018    # endregion
1019    ###################################################################################
1020    ###################################################################################
1021    # region Recursive getters
1022    ###################################################################################
1023    ###################################################################################
1024
1025    @property
1026    def all_functions_called(self) -> List["InternalCallType"]:
1027        """
1028        list(Function): List of functions reachable from the contract
1029        Includes super, and private/internal functions not shadowed
1030        """
1031        if self._all_functions_called is None:
1032            all_functions = [f for f in self.functions + self.modifiers if not f.is_shadowed]  # type: ignore
1033            all_callss = [f.all_internal_calls() for f in all_functions] + [list(all_functions)]
1034            all_calls = [item for sublist in all_callss for item in sublist]
1035            all_calls = list(set(all_calls))
1036
1037            all_constructors = [c.constructor for c in self.inheritance if c.constructor]
1038            all_constructors = list(set(all_constructors))
1039
1040            set_all_calls = set(all_calls + list(all_constructors))
1041
1042            self._all_functions_called = [c for c in set_all_calls if isinstance(c, Function)]
1043        return self._all_functions_called
1044
1045    @property
1046    def all_state_variables_written(self) -> List["StateVariable"]:
1047        """
1048        list(StateVariable): List all of the state variables written
1049        """
1050        all_state_variables_writtens = [
1051            f.all_state_variables_written() for f in self.functions + self.modifiers  # type: ignore
1052        ]
1053        all_state_variables_written = [
1054            item for sublist in all_state_variables_writtens for item in sublist
1055        ]
1056        return list(set(all_state_variables_written))
1057
1058    @property
1059    def all_state_variables_read(self) -> List["StateVariable"]:
1060        """
1061        list(StateVariable): List all of the state variables read
1062        """
1063        all_state_variables_reads = [
1064            f.all_state_variables_read() for f in self.functions + self.modifiers  # type: ignore
1065        ]
1066        all_state_variables_read = [
1067            item for sublist in all_state_variables_reads for item in sublist
1068        ]
1069        return list(set(all_state_variables_read))
1070
1071    @property
1072    def all_library_calls(self) -> List["LibraryCallType"]:
1073        """
1074        list((Contract, Function): List all of the libraries func called
1075        """
1076        all_high_level_callss = [f.all_library_calls() for f in self.functions + self.modifiers]  # type: ignore
1077        all_high_level_calls = [item for sublist in all_high_level_callss for item in sublist]
1078        return list(set(all_high_level_calls))
1079
1080    @property
1081    def all_high_level_calls(self) -> List["HighLevelCallType"]:
1082        """
1083        list((Contract, Function|Variable)): List all of the external high level calls
1084        """
1085        all_high_level_callss = [f.all_high_level_calls() for f in self.functions + self.modifiers]  # type: ignore
1086        all_high_level_calls = [item for sublist in all_high_level_callss for item in sublist]
1087        return list(set(all_high_level_calls))
1088
1089    # endregion
1090    ###################################################################################
1091    ###################################################################################
1092    # region Summary information
1093    ###################################################################################
1094    ###################################################################################
1095
1096    def get_summary(
1097        self, include_shadowed: bool = True
1098    ) -> Tuple[str, List[str], List[str], List, List]:
1099        """Return the function summary
1100
1101        :param include_shadowed: boolean to indicate if shadowed functions should be included (default True)
1102        Returns:
1103            (str, list, list, list, list): (name, inheritance, variables, fuction summaries, modifier summaries)
1104        """
1105        func_summaries = [
1106            f.get_summary() for f in self.functions if (not f.is_shadowed or include_shadowed)
1107        ]
1108        modif_summaries = [
1109            f.get_summary() for f in self.modifiers if (not f.is_shadowed or include_shadowed)
1110        ]
1111        return (
1112            self.name,
1113            [str(x) for x in self.inheritance],
1114            [str(x) for x in self.variables],
1115            func_summaries,
1116            modif_summaries,
1117        )
1118
1119    def is_signature_only(self) -> bool:
1120        """Detect if the contract has only abstract functions
1121
1122        Returns:
1123            bool: true if the function are abstract functions
1124        """
1125        return all((not f.is_implemented) for f in self.functions)
1126
1127    # endregion
1128    ###################################################################################
1129    ###################################################################################
1130    # region ERC conformance
1131    ###################################################################################
1132    ###################################################################################
1133
1134    def ercs(self) -> List[str]:
1135        """
1136        Return the ERC implemented
1137        :return: list of string
1138        """
1139        all_erc = [
1140            ("ERC20", self.is_erc20),
1141            ("ERC165", self.is_erc165),
1142            ("ERC1820", self.is_erc1820),
1143            ("ERC223", self.is_erc223),
1144            ("ERC721", self.is_erc721),
1145            ("ERC777", self.is_erc777),
1146            ("ERC2612", self.is_erc2612),
1147            ("ERC1363", self.is_erc1363),
1148            ("ERC4626", self.is_erc4626),
1149        ]
1150
1151        return [erc for erc, is_erc in all_erc if is_erc()]
1152
1153    def is_erc20(self) -> bool:
1154        """
1155            Check if the contract is an erc20 token
1156
1157            Note: it does not check for correct return values
1158        :return: Returns a true if the contract is an erc20
1159        """
1160        full_names = self.functions_signatures
1161        return all(s in full_names for s in ERC20_signatures)
1162
1163    def is_erc165(self) -> bool:
1164        """
1165            Check if the contract is an erc165 token
1166
1167            Note: it does not check for correct return values
1168        :return: Returns a true if the contract is an erc165
1169        """
1170        full_names = self.functions_signatures
1171        return all(s in full_names for s in ERC165_signatures)
1172
1173    def is_erc1820(self) -> bool:
1174        """
1175            Check if the contract is an erc1820
1176
1177            Note: it does not check for correct return values
1178        :return: Returns a true if the contract is an erc165
1179        """
1180        full_names = self.functions_signatures
1181        return all(s in full_names for s in ERC1820_signatures)
1182
1183    def is_erc223(self) -> bool:
1184        """
1185            Check if the contract is an erc223 token
1186
1187            Note: it does not check for correct return values
1188        :return: Returns a true if the contract is an erc223
1189        """
1190        full_names = self.functions_signatures
1191        return all(s in full_names for s in ERC223_signatures)
1192
1193    def is_erc721(self) -> bool:
1194        """
1195            Check if the contract is an erc721 token
1196
1197            Note: it does not check for correct return values
1198        :return: Returns a true if the contract is an erc721
1199        """
1200        full_names = self.functions_signatures
1201        return all(s in full_names for s in ERC721_signatures)
1202
1203    def is_erc777(self) -> bool:
1204        """
1205            Check if the contract is an erc777
1206
1207            Note: it does not check for correct return values
1208        :return: Returns a true if the contract is an erc165
1209        """
1210        full_names = self.functions_signatures
1211        return all(s in full_names for s in ERC777_signatures)
1212
1213    def is_erc1155(self) -> bool:
1214        """
1215            Check if the contract is an erc1155
1216
1217            Note: it does not check for correct return values
1218        :return: Returns a true if the contract is an erc1155
1219        """
1220        full_names = self.functions_signatures
1221        return all(s in full_names for s in ERC1155_signatures)
1222
1223    def is_erc4626(self) -> bool:
1224        """
1225            Check if the contract is an erc4626
1226
1227            Note: it does not check for correct return values
1228        :return: Returns a true if the contract is an erc4626
1229        """
1230        full_names = self.functions_signatures
1231        return all(s in full_names for s in ERC4626_signatures)
1232
1233    def is_erc2612(self) -> bool:
1234        """
1235            Check if the contract is an erc2612
1236
1237            Note: it does not check for correct return values
1238        :return: Returns a true if the contract is an erc2612
1239        """
1240        full_names = self.functions_signatures
1241        return all(s in full_names for s in ERC2612_signatures)
1242
1243    def is_erc1363(self) -> bool:
1244        """
1245            Check if the contract is an erc1363
1246
1247            Note: it does not check for correct return values
1248        :return: Returns a true if the contract is an erc1363
1249        """
1250        full_names = self.functions_signatures
1251        return all(s in full_names for s in ERC1363_signatures)
1252
1253    def is_erc4524(self) -> bool:
1254        """
1255            Check if the contract is an erc4524
1256
1257            Note: it does not check for correct return values
1258        :return: Returns a true if the contract is an erc4524
1259        """
1260        full_names = self.functions_signatures
1261        return all(s in full_names for s in ERC4524_signatures)
1262
1263    @property
1264    def is_token(self) -> bool:
1265        """
1266        Check if the contract follows one of the standard ERC token
1267        :return:
1268        """
1269        return (
1270            self.is_erc20()
1271            or self.is_erc721()
1272            or self.is_erc165()
1273            or self.is_erc223()
1274            or self.is_erc777()
1275            or self.is_erc1155()
1276        )
1277
1278    def is_possible_erc20(self) -> bool:
1279        """
1280        Checks if the provided contract could be attempting to implement ERC20 standards.
1281
1282        :return: Returns a boolean indicating if the provided contract met the token standard.
1283        """
1284        # We do not check for all the functions, as name(), symbol(), might give too many FPs
1285        full_names = self.functions_signatures
1286        return (
1287            "transfer(address,uint256)" in full_names
1288            or "transferFrom(address,address,uint256)" in full_names
1289            or "approve(address,uint256)" in full_names
1290        )
1291
1292    def is_possible_erc721(self) -> bool:
1293        """
1294        Checks if the provided contract could be attempting to implement ERC721 standards.
1295
1296        :return: Returns a boolean indicating if the provided contract met the token standard.
1297        """
1298        # We do not check for all the functions, as name(), symbol(), might give too many FPs
1299        full_names = self.functions_signatures
1300        return (
1301            "ownerOf(uint256)" in full_names
1302            or "safeTransferFrom(address,address,uint256,bytes)" in full_names
1303            or "safeTransferFrom(address,address,uint256)" in full_names
1304            or "setApprovalForAll(address,bool)" in full_names
1305            or "getApproved(uint256)" in full_names
1306            or "isApprovedForAll(address,address)" in full_names
1307        )
1308
1309    @property
1310    def is_possible_token(self) -> bool:
1311        """
1312        Check if the contract is a potential token (it might not implement all the functions)
1313        :return:
1314        """
1315        return self.is_possible_erc20() or self.is_possible_erc721()
1316
1317    # endregion
1318    ###################################################################################
1319    ###################################################################################
1320    # region Dependencies
1321    ###################################################################################
1322    ###################################################################################
1323
1324    def is_from_dependency(self) -> bool:
1325        return self.compilation_unit.core.crytic_compile.is_dependency(
1326            self.source_mapping.filename.absolute
1327        )
1328
1329    # endregion
1330    ###################################################################################
1331    ###################################################################################
1332    # region Test
1333    ###################################################################################
1334    ###################################################################################
1335
1336    @property
1337    def is_truffle_migration(self) -> bool:
1338        """
1339        Return true if the contract is the Migrations contract needed for Truffle
1340        :return:
1341        """
1342        if self.compilation_unit.core.crytic_compile.platform == PlatformType.TRUFFLE:
1343            if self.name == "Migrations":
1344                paths = Path(self.source_mapping.filename.absolute).parts
1345                if len(paths) >= 2:
1346                    return paths[-2] == "contracts" and paths[-1] == "migrations.sol"
1347        return False
1348
1349    @property
1350    def is_test(self) -> bool:
1351        return is_test_contract(self) or self.is_truffle_migration  # type: ignore
1352
1353    # endregion
1354    ###################################################################################
1355    ###################################################################################
1356    # region Function analyses
1357    ###################################################################################
1358    ###################################################################################
1359
1360    def update_read_write_using_ssa(self) -> None:
1361        for function in self.functions + list(self.modifiers):
1362            function.update_read_write_using_ssa()
1363
1364    # endregion
1365    ###################################################################################
1366    ###################################################################################
1367    # region Upgradeability
1368    ###################################################################################
1369    ###################################################################################
1370
1371    @property
1372    def is_upgradeable(self) -> bool:
1373        if self._is_upgradeable is None:
1374            self._is_upgradeable = False
1375            initializable = self.file_scope.get_contract_from_name("Initializable")
1376            if initializable:
1377                if initializable in self.inheritance:
1378                    self._is_upgradeable = True
1379            else:
1380                for contract in self.inheritance + [self]:
1381                    # This might lead to false positive
1382                    # Not sure why pylint is having a trouble here
1383                    # pylint: disable=no-member
1384                    lower_name = contract.name.lower()
1385                    if "upgradeable" in lower_name or "upgradable" in lower_name:
1386                        self._is_upgradeable = True
1387                        break
1388                    if "initializable" in lower_name:
1389                        self._is_upgradeable = True
1390                        break
1391        return self._is_upgradeable
1392
1393    @is_upgradeable.setter
1394    def is_upgradeable(self, upgradeable: bool) -> None:
1395        self._is_upgradeable = upgradeable
1396
1397    @property
1398    def is_upgradeable_proxy(self) -> bool:
1399        from slither.core.cfg.node import NodeType
1400        from slither.slithir.operations import LowLevelCall
1401
1402        if self._is_upgradeable_proxy is None:
1403            self._is_upgradeable_proxy = False
1404            if "Proxy" in self.name:
1405                self._is_upgradeable_proxy = True
1406                return True
1407            for f in self.functions:
1408                if f.is_fallback:
1409                    for node in f.all_nodes():
1410                        for ir in node.irs:
1411                            if isinstance(ir, LowLevelCall) and ir.function_name == "delegatecall":
1412                                self._is_upgradeable_proxy = True
1413                                return self._is_upgradeable_proxy
1414                        if node.type == NodeType.ASSEMBLY:
1415                            inline_asm = node.inline_asm
1416                            if inline_asm:
1417                                if "delegatecall" in inline_asm:
1418                                    self._is_upgradeable_proxy = True
1419                                    return self._is_upgradeable_proxy
1420        return self._is_upgradeable_proxy
1421
1422    @is_upgradeable_proxy.setter
1423    def is_upgradeable_proxy(self, upgradeable_proxy: bool) -> None:
1424        self._is_upgradeable_proxy = upgradeable_proxy
1425
1426    @property
1427    def upgradeable_version(self) -> Optional[str]:
1428        return self._upgradeable_version
1429
1430    @upgradeable_version.setter
1431    def upgradeable_version(self, version_name: str) -> None:
1432        self._upgradeable_version = version_name
1433
1434    # endregion
1435    ###################################################################################
1436    ###################################################################################
1437    # region Internals
1438    ###################################################################################
1439    ###################################################################################
1440
1441    @property
1442    def is_incorrectly_constructed(self) -> bool:
1443        """
1444        Return true if there was an internal Slither's issue when analyzing the contract
1445        :return:
1446        """
1447        return self._is_incorrectly_parsed
1448
1449    @is_incorrectly_constructed.setter
1450    def is_incorrectly_constructed(self, incorrect: bool) -> None:
1451        self._is_incorrectly_parsed = incorrect
1452
1453    def add_constructor_variables(self) -> None:
1454        from slither.core.declarations.function_contract import FunctionContract
1455
1456        if self.state_variables:
1457            for (idx, variable_candidate) in enumerate(self.state_variables):
1458                if variable_candidate.expression and not variable_candidate.is_constant:
1459
1460                    constructor_variable = FunctionContract(self.compilation_unit)
1461                    constructor_variable.set_function_type(FunctionType.CONSTRUCTOR_VARIABLES)
1462                    constructor_variable.set_contract(self)  # type: ignore
1463                    constructor_variable.set_contract_declarer(self)  # type: ignore
1464                    constructor_variable.set_visibility("internal")
1465                    # For now, source mapping of the constructor variable is the whole contract
1466                    # Could be improved with a targeted source mapping
1467                    constructor_variable.set_offset(self.source_mapping, self.compilation_unit)
1468                    self._functions[constructor_variable.canonical_name] = constructor_variable
1469
1470                    prev_node = self._create_node(
1471                        constructor_variable, 0, variable_candidate, constructor_variable
1472                    )
1473                    variable_candidate.node_initialization = prev_node
1474                    counter = 1
1475                    for v in self.state_variables[idx + 1 :]:
1476                        if v.expression and not v.is_constant:
1477                            next_node = self._create_node(
1478                                constructor_variable, counter, v, prev_node.scope
1479                            )
1480                            v.node_initialization = next_node
1481                            prev_node.add_son(next_node)
1482                            next_node.add_father(prev_node)
1483                            prev_node = next_node
1484                            counter += 1
1485                    break
1486
1487            for (idx, variable_candidate) in enumerate(self.state_variables):
1488                if variable_candidate.expression and variable_candidate.is_constant:
1489
1490                    constructor_variable = FunctionContract(self.compilation_unit)
1491                    constructor_variable.set_function_type(
1492                        FunctionType.CONSTRUCTOR_CONSTANT_VARIABLES
1493                    )
1494                    constructor_variable.set_contract(self)  # type: ignore
1495                    constructor_variable.set_contract_declarer(self)  # type: ignore
1496                    constructor_variable.set_visibility("internal")
1497                    # For now, source mapping of the constructor variable is the whole contract
1498                    # Could be improved with a targeted source mapping
1499                    constructor_variable.set_offset(self.source_mapping, self.compilation_unit)
1500                    self._functions[constructor_variable.canonical_name] = constructor_variable
1501
1502                    prev_node = self._create_node(
1503                        constructor_variable, 0, variable_candidate, constructor_variable
1504                    )
1505                    variable_candidate.node_initialization = prev_node
1506                    counter = 1
1507                    for v in self.state_variables[idx + 1 :]:
1508                        if v.expression and v.is_constant:
1509                            next_node = self._create_node(
1510                                constructor_variable, counter, v, prev_node.scope
1511                            )
1512                            v.node_initialization = next_node
1513                            prev_node.add_son(next_node)
1514                            next_node.add_father(prev_node)
1515                            prev_node = next_node
1516                            counter += 1
1517
1518                    break
1519
1520    def _create_node(
1521        self, func: Function, counter: int, variable: "Variable", scope: Union[Scope, Function]
1522    ) -> "Node":
1523        from slither.core.cfg.node import Node, NodeType
1524        from slither.core.expressions import (
1525            AssignmentOperationType,
1526            AssignmentOperation,
1527            Identifier,
1528        )
1529
1530        # Function uses to create node for state variable declaration statements
1531        node = Node(NodeType.OTHER_ENTRYPOINT, counter, scope, func.file_scope)
1532        node.set_offset(variable.source_mapping, self.compilation_unit)
1533        node.set_function(func)
1534        func.add_node(node)
1535        assert variable.expression
1536        expression = AssignmentOperation(
1537            Identifier(variable),
1538            variable.expression,
1539            AssignmentOperationType.ASSIGN,
1540            variable.type,
1541        )
1542
1543        expression.set_offset(variable.source_mapping, self.compilation_unit)
1544        node.add_expression(expression)
1545        return node
1546
1547    # endregion
1548    ###################################################################################
1549    ###################################################################################
1550    # region SlithIR
1551    ###################################################################################
1552    ###################################################################################
1553
1554    def convert_expression_to_slithir_ssa(self) -> None:
1555        """
1556        Assume generate_slithir_and_analyze was called on all functions
1557
1558        :return:
1559        """
1560        from slither.slithir.variables import StateIRVariable
1561
1562        all_ssa_state_variables_instances = {}
1563
1564        for contract in self.inheritance:
1565            for v in contract.state_variables_declared:
1566                new_var = StateIRVariable(v)
1567                all_ssa_state_variables_instances[v.canonical_name] = new_var
1568                self._initial_state_variables.append(new_var)
1569
1570        for v in self.variables:
1571            if v.contract == self:
1572                new_var = StateIRVariable(v)
1573                all_ssa_state_variables_instances[v.canonical_name] = new_var
1574                self._initial_state_variables.append(new_var)
1575
1576        for func in self.functions + list(self.modifiers):
1577            func.generate_slithir_ssa(all_ssa_state_variables_instances)
1578
1579    def fix_phi(self) -> None:
1580        last_state_variables_instances: Dict[str, List["StateVariable"]] = {}
1581        initial_state_variables_instances: Dict[str, "StateVariable"] = {}
1582        for v in self._initial_state_variables:
1583            last_state_variables_instances[v.canonical_name] = []
1584            initial_state_variables_instances[v.canonical_name] = v
1585
1586        for func in self.functions + list(self.modifiers):
1587            result = func.get_last_ssa_state_variables_instances()
1588            for variable_name, instances in result.items():
1589                # TODO: investigate the next operation
1590                last_state_variables_instances[variable_name] += list(instances)
1591
1592        for func in self.functions + list(self.modifiers):
1593            func.fix_phi(last_state_variables_instances, initial_state_variables_instances)
1594
1595    # endregion
1596    ###################################################################################
1597    ###################################################################################
1598    # region Built in definitions
1599    ###################################################################################
1600    ###################################################################################
1601
1602    def __eq__(self, other: Any) -> bool:
1603        if isinstance(other, str):
1604            return other == self.name
1605        return NotImplemented
1606
1607    def __neq__(self, other: Any) -> bool:
1608        if isinstance(other, str):
1609            return other != self.name
1610        return NotImplemented
1611
1612    def __str__(self) -> str:
1613        return self.name
1614
1615    def __hash__(self) -> int:
1616        return self._id  # type:ignore
1617
1618    # endregion
LOGGER = <Logger Contract (WARNING)>
  54class Contract(SourceMapping):  # pylint: disable=too-many-public-methods
  55    """
  56    Contract class
  57    """
  58
  59    def __init__(self, compilation_unit: "SlitherCompilationUnit", scope: "FileScope") -> None:
  60        super().__init__()
  61
  62        self._name: Optional[str] = None
  63        self._id: Optional[int] = None
  64        self._inheritance: List["Contract"] = []  # all contract inherited, c3 linearization
  65        self._immediate_inheritance: List["Contract"] = []  # immediate inheritance
  66
  67        # Constructors called on contract's definition
  68        # contract B is A(1) { ..
  69        self._explicit_base_constructor_calls: List["Contract"] = []
  70
  71        self._enums: Dict[str, "EnumContract"] = {}
  72        self._structures: Dict[str, "StructureContract"] = {}
  73        self._events: Dict[str, "EventContract"] = {}
  74        # map accessible variable from name -> variable
  75        # do not contain private variables inherited from contract
  76        self._variables: Dict[str, "StateVariable"] = {}
  77        self._variables_ordered: List["StateVariable"] = []
  78        # Reference id -> variable declaration (only available for compact AST)
  79        self._state_variables_by_ref_id: Dict[int, "StateVariable"] = {}
  80        self._modifiers: Dict[str, "Modifier"] = {}
  81        self._functions: Dict[str, "FunctionContract"] = {}
  82        self._linearizedBaseContracts: List[int] = []
  83        self._custom_errors: Dict[str, "CustomErrorContract"] = {}
  84        self._type_aliases: Dict[str, "TypeAliasContract"] = {}
  85
  86        # The only str is "*"
  87        self._using_for: USING_FOR = {}
  88        self._using_for_complete: Optional[USING_FOR] = None
  89        self._kind: Optional[str] = None
  90        self._is_interface: bool = False
  91        self._is_library: bool = False
  92        self._is_fully_implemented: bool = False
  93        self._is_abstract: bool = False
  94
  95        self._signatures: Optional[List[str]] = None
  96        self._signatures_declared: Optional[List[str]] = None
  97
  98        self._fallback_function: Optional["FunctionContract"] = None
  99        self._receive_function: Optional["FunctionContract"] = None
 100
 101        self._is_upgradeable: Optional[bool] = None
 102        self._is_upgradeable_proxy: Optional[bool] = None
 103        self._upgradeable_version: Optional[str] = None
 104
 105        self._initial_state_variables: List["StateVariable"] = []  # ssa
 106
 107        self._is_incorrectly_parsed: bool = False
 108
 109        self._available_functions_as_dict: Optional[Dict[str, "Function"]] = None
 110        self._all_functions_called: Optional[List["InternalCallType"]] = None
 111
 112        self.compilation_unit: "SlitherCompilationUnit" = compilation_unit
 113        self.file_scope: "FileScope" = scope
 114
 115        # memoize
 116        self._state_variables_used_in_reentrant_targets: Optional[
 117            Dict["StateVariable", Set[Union["StateVariable", "Function"]]]
 118        ] = None
 119
 120        self._comments: Optional[str] = None
 121
 122    ###################################################################################
 123    ###################################################################################
 124    # region General's properties
 125    ###################################################################################
 126    ###################################################################################
 127
 128    @property
 129    def name(self) -> str:
 130        """str: Name of the contract."""
 131        assert self._name
 132        return self._name
 133
 134    @name.setter
 135    def name(self, name: str) -> None:
 136        self._name = name
 137
 138    @property
 139    def id(self) -> int:
 140        """Unique id."""
 141        assert self._id is not None
 142        return self._id
 143
 144    @id.setter
 145    def id(self, new_id: int) -> None:
 146        """Unique id."""
 147        self._id = new_id
 148
 149    @property
 150    def contract_kind(self) -> Optional[str]:
 151        """
 152        contract_kind can be None if the legacy ast format is used
 153        :return:
 154        """
 155        return self._kind
 156
 157    @contract_kind.setter
 158    def contract_kind(self, kind: str) -> None:
 159        self._kind = kind
 160
 161    @property
 162    def is_interface(self) -> bool:
 163        return self._is_interface
 164
 165    @is_interface.setter
 166    def is_interface(self, is_interface: bool) -> None:
 167        self._is_interface = is_interface
 168
 169    @property
 170    def is_library(self) -> bool:
 171        return self._is_library
 172
 173    @is_library.setter
 174    def is_library(self, is_library: bool) -> None:
 175        self._is_library = is_library
 176
 177    @property
 178    def comments(self) -> Optional[str]:
 179        """
 180        Return the comments associated with the contract.
 181
 182        When using comments, avoid strict text matching, as the solc behavior might change.
 183        For example, for old solc version, the first space after the * is not kept, i.e:
 184
 185          * @title Test Contract
 186          * @dev Test comment
 187
 188        Returns
 189        - " @title Test Contract\n @dev Test comment" for newest versions
 190        - "@title Test Contract\n@dev Test comment" for older versions
 191
 192
 193        Returns:
 194            the comment as a string
 195        """
 196        return self._comments
 197
 198    @comments.setter
 199    def comments(self, comments: str):
 200        self._comments = comments
 201
 202    @property
 203    def is_fully_implemented(self) -> bool:
 204        """
 205        bool: True if the contract defines all functions.
 206        In modern Solidity, virtual functions can lack an implementation.
 207        Prior to Solidity 0.6.0, functions like the following would be not fully implemented:
 208        ```solidity
 209        contract ImplicitAbstract{
 210            function f() public;
 211        }
 212        ```
 213        """
 214        return self._is_fully_implemented
 215
 216    @is_fully_implemented.setter
 217    def is_fully_implemented(self, is_fully_implemented: bool):
 218        self._is_fully_implemented = is_fully_implemented
 219
 220    @property
 221    def is_abstract(self) -> bool:
 222        """
 223        Note for Solidity < 0.6.0 it will always be false
 224        bool: True if the contract is abstract.
 225        """
 226        return self._is_abstract
 227
 228    @is_abstract.setter
 229    def is_abstract(self, is_abstract: bool):
 230        self._is_abstract = is_abstract
 231
 232    # endregion
 233    ###################################################################################
 234    ###################################################################################
 235    # region Structures
 236    ###################################################################################
 237    ###################################################################################
 238
 239    @property
 240    def structures(self) -> List["StructureContract"]:
 241        """
 242        list(Structure): List of the structures
 243        """
 244        return list(self._structures.values())
 245
 246    @property
 247    def structures_inherited(self) -> List["StructureContract"]:
 248        """
 249        list(Structure): List of the inherited structures
 250        """
 251        return [s for s in self.structures if s.contract != self]
 252
 253    @property
 254    def structures_declared(self) -> List["StructureContract"]:
 255        """
 256        list(Structues): List of the structures declared within the contract (not inherited)
 257        """
 258        return [s for s in self.structures if s.contract == self]
 259
 260    @property
 261    def structures_as_dict(self) -> Dict[str, "StructureContract"]:
 262        return self._structures
 263
 264    # endregion
 265    ###################################################################################
 266    ###################################################################################
 267    # region Enums
 268    ###################################################################################
 269    ###################################################################################
 270
 271    @property
 272    def enums(self) -> List["EnumContract"]:
 273        return list(self._enums.values())
 274
 275    @property
 276    def enums_inherited(self) -> List["EnumContract"]:
 277        """
 278        list(Enum): List of the inherited enums
 279        """
 280        return [e for e in self.enums if e.contract != self]
 281
 282    @property
 283    def enums_declared(self) -> List["EnumContract"]:
 284        """
 285        list(Enum): List of the enums declared within the contract (not inherited)
 286        """
 287        return [e for e in self.enums if e.contract == self]
 288
 289    @property
 290    def enums_as_dict(self) -> Dict[str, "EnumContract"]:
 291        return self._enums
 292
 293    # endregion
 294    ###################################################################################
 295    ###################################################################################
 296    # region Events
 297    ###################################################################################
 298    ###################################################################################
 299
 300    @property
 301    def events(self) -> List["EventContract"]:
 302        """
 303        list(Event): List of the events
 304        """
 305        return list(self._events.values())
 306
 307    @property
 308    def events_inherited(self) -> List["EventContract"]:
 309        """
 310        list(Event): List of the inherited events
 311        """
 312        return [e for e in self.events if e.contract != self]
 313
 314    @property
 315    def events_declared(self) -> List["EventContract"]:
 316        """
 317        list(Event): List of the events declared within the contract (not inherited)
 318        """
 319        return [e for e in self.events if e.contract == self]
 320
 321    @property
 322    def events_as_dict(self) -> Dict[str, "EventContract"]:
 323        return self._events
 324
 325    # endregion
 326    ###################################################################################
 327    ###################################################################################
 328    # region Using for
 329    ###################################################################################
 330    ###################################################################################
 331
 332    @property
 333    def using_for(self) -> USING_FOR:
 334        return self._using_for
 335
 336    @property
 337    def using_for_complete(self) -> USING_FOR:
 338        """
 339        USING_FOR: Dict of merged local using for directive with top level directive
 340        """
 341
 342        if self._using_for_complete is None:
 343            result = self.using_for
 344            top_level_using_for = self.file_scope.using_for_directives
 345            for uftl in top_level_using_for:
 346                result = merge_using_for(result, uftl.using_for)
 347            self._using_for_complete = result
 348        return self._using_for_complete
 349
 350    # endregion
 351    ###################################################################################
 352    ###################################################################################
 353    # region Custom Errors
 354    ###################################################################################
 355    ###################################################################################
 356
 357    @property
 358    def custom_errors(self) -> List["CustomErrorContract"]:
 359        """
 360        list(CustomErrorContract): List of the contract's custom errors
 361        """
 362        return list(self._custom_errors.values())
 363
 364    @property
 365    def custom_errors_inherited(self) -> List["CustomErrorContract"]:
 366        """
 367        list(CustomErrorContract): List of the inherited custom errors
 368        """
 369        return [s for s in self.custom_errors if s.contract != self]
 370
 371    @property
 372    def custom_errors_declared(self) -> List["CustomErrorContract"]:
 373        """
 374        list(CustomErrorContract): List of the custom errors declared within the contract (not inherited)
 375        """
 376        return [s for s in self.custom_errors if s.contract == self]
 377
 378    @property
 379    def custom_errors_as_dict(self) -> Dict[str, "CustomErrorContract"]:
 380        return self._custom_errors
 381
 382    # endregion
 383    ###################################################################################
 384    ###################################################################################
 385    # region Custom Errors
 386    ###################################################################################
 387    ###################################################################################
 388
 389    @property
 390    def type_aliases(self) -> List["TypeAliasContract"]:
 391        """
 392        list(TypeAliasContract): List of the contract's custom errors
 393        """
 394        return list(self._type_aliases.values())
 395
 396    @property
 397    def type_aliases_inherited(self) -> List["TypeAliasContract"]:
 398        """
 399        list(TypeAliasContract): List of the inherited custom errors
 400        """
 401        return [s for s in self.type_aliases if s.contract != self]
 402
 403    @property
 404    def type_aliases_declared(self) -> List["TypeAliasContract"]:
 405        """
 406        list(TypeAliasContract): List of the custom errors declared within the contract (not inherited)
 407        """
 408        return [s for s in self.type_aliases if s.contract == self]
 409
 410    @property
 411    def type_aliases_as_dict(self) -> Dict[str, "TypeAliasContract"]:
 412        return self._type_aliases
 413
 414    # endregion
 415    ###################################################################################
 416    ###################################################################################
 417    # region Variables
 418    ###################################################################################
 419    ###################################################################################
 420    @property
 421    def state_variables_by_ref_id(self) -> Dict[int, "StateVariable"]:
 422        """
 423        Returns the state variables by reference id (only available for compact AST).
 424        """
 425        return self._state_variables_by_ref_id
 426
 427    @property
 428    def variables(self) -> List["StateVariable"]:
 429        """
 430        Returns all the accessible variables (do not include private variable from inherited contract)
 431
 432        list(StateVariable): List of the state variables. Alias to self.state_variables.
 433        """
 434        return list(self.state_variables)
 435
 436    @property
 437    def variables_as_dict(self) -> Dict[str, "StateVariable"]:
 438        return self._variables
 439
 440    @property
 441    def state_variables(self) -> List["StateVariable"]:
 442        """
 443        Returns all the accessible variables (do not include private variable from inherited contract).
 444        Use state_variables_ordered for all the variables following the storage order
 445
 446        list(StateVariable): List of the state variables.
 447        """
 448        return list(self._variables.values())
 449
 450    @property
 451    def stored_state_variables(self) -> List["StateVariable"]:
 452        """
 453        Returns state variables with storage locations, excluding private variables from inherited contracts.
 454        Use stored_state_variables_ordered to access variables with storage locations in their declaration order.
 455
 456        This implementation filters out state variables if they are constant or immutable. It will be
 457        updated to accommodate any new non-storage keywords that might replace 'constant' and 'immutable' in the future.
 458
 459        Returns:
 460            List[StateVariable]: A list of state variables with storage locations.
 461        """
 462        return [variable for variable in self.state_variables if variable.is_stored]
 463
 464    @property
 465    def stored_state_variables_ordered(self) -> List["StateVariable"]:
 466        """
 467        list(StateVariable): List of the state variables with storage locations by order of declaration.
 468
 469        This implementation filters out state variables if they are constant or immutable. It will be
 470        updated to accommodate any new non-storage keywords that might replace 'constant' and 'immutable' in the future.
 471
 472        Returns:
 473            List[StateVariable]: A list of state variables with storage locations ordered by declaration.
 474        """
 475        return [variable for variable in self.state_variables_ordered if variable.is_stored]
 476
 477    @property
 478    def state_variables_entry_points(self) -> List["StateVariable"]:
 479        """
 480        list(StateVariable): List of the state variables that are public.
 481        """
 482        return [var for var in self._variables.values() if var.visibility == "public"]
 483
 484    @property
 485    def state_variables_ordered(self) -> List["StateVariable"]:
 486        """
 487        list(StateVariable): List of the state variables by order of declaration.
 488        """
 489        return list(self._variables_ordered)
 490
 491    def add_variables_ordered(self, new_vars: List["StateVariable"]) -> None:
 492        self._variables_ordered += new_vars
 493
 494    @property
 495    def state_variables_inherited(self) -> List["StateVariable"]:
 496        """
 497        list(StateVariable): List of the inherited state variables
 498        """
 499        return [s for s in self.state_variables if s.contract != self]
 500
 501    @property
 502    def state_variables_declared(self) -> List["StateVariable"]:
 503        """
 504        list(StateVariable): List of the state variables declared within the contract (not inherited)
 505        """
 506        return [s for s in self.state_variables if s.contract == self]
 507
 508    @property
 509    def slithir_variables(self) -> List["SlithIRVariable"]:
 510        """
 511        List all of the slithir variables (non SSA)
 512        """
 513        slithir_variabless = [f.slithir_variables for f in self.functions + self.modifiers]  # type: ignore
 514        slithir_variables = [item for sublist in slithir_variabless for item in sublist]
 515        return list(set(slithir_variables))
 516
 517    @property
 518    def state_variables_used_in_reentrant_targets(
 519        self,
 520    ) -> Dict["StateVariable", Set[Union["StateVariable", "Function"]]]:
 521        """
 522        Returns the state variables used in reentrant targets. Heuristics:
 523        - Variable used (read/write) in entry points that are reentrant
 524        - State variables that are public
 525
 526        """
 527        from slither.core.variables.state_variable import StateVariable
 528
 529        if self._state_variables_used_in_reentrant_targets is None:
 530            reentrant_functions = [f for f in self.functions_entry_points if f.is_reentrant]
 531            variables_used: Dict[
 532                StateVariable, Set[Union[StateVariable, "Function"]]
 533            ] = defaultdict(set)
 534            for function in reentrant_functions:
 535                for ir in function.all_slithir_operations():
 536                    state_variables = [v for v in ir.used if isinstance(v, StateVariable)]
 537                    for state_variable in state_variables:
 538                        variables_used[state_variable].add(ir.node.function)
 539            for variable in [v for v in self.state_variables if v.visibility == "public"]:
 540                variables_used[variable].add(variable)
 541            self._state_variables_used_in_reentrant_targets = variables_used
 542        return self._state_variables_used_in_reentrant_targets
 543
 544    # endregion
 545    ###################################################################################
 546    ###################################################################################
 547    # region Constructors
 548    ###################################################################################
 549    ###################################################################################
 550
 551    @property
 552    def constructor(self) -> Optional["Function"]:
 553        """
 554        Return the contract's immediate constructor.
 555        If there is no immediate constructor, returns the first constructor
 556        executed, following the c3 linearization
 557        Return None if there is no constructor.
 558        """
 559        cst = self.constructors_declared
 560        if cst:
 561            return cst
 562        for inherited_contract in self.inheritance:
 563            cst = inherited_contract.constructors_declared
 564            if cst:
 565                return cst
 566        return None
 567
 568    @property
 569    def constructors_declared(self) -> Optional["Function"]:
 570        return next(
 571            (
 572                func
 573                for func in self.functions
 574                if func.is_constructor and func.contract_declarer == self
 575            ),
 576            None,
 577        )
 578
 579    @property
 580    def constructors(self) -> List["FunctionContract"]:
 581        """
 582        Return the list of constructors (including inherited)
 583        """
 584        return [func for func in self.functions if func.is_constructor]
 585
 586    @property
 587    def explicit_base_constructor_calls(self) -> List["Function"]:
 588        """
 589        list(Function): List of the base constructors called explicitly by this contract definition.
 590
 591                        Base constructors called by any constructor definition will not be included.
 592                        Base constructors implicitly called by the contract definition (without
 593                        parenthesis) will not be included.
 594
 595                        On "contract B is A(){..}" it returns the constructor of A
 596        """
 597        return [c.constructor for c in self._explicit_base_constructor_calls if c.constructor]
 598
 599    # endregion
 600    ###################################################################################
 601    ###################################################################################
 602    # region Functions and Modifiers
 603    ###################################################################################
 604    ###################################################################################
 605
 606    @property
 607    def functions_signatures(self) -> List[str]:
 608        """
 609        Return the signatures of all the public/eterxnal functions/state variables
 610        :return: list(string) the signatures of all the functions that can be called
 611        """
 612        if self._signatures is None:
 613            sigs = [
 614                v.full_name for v in self.state_variables if v.visibility in ["public", "external"]
 615            ]
 616
 617            sigs += {f.full_name for f in self.functions if f.visibility in ["public", "external"]}
 618            self._signatures = list(set(sigs))
 619        return self._signatures
 620
 621    @property
 622    def functions_signatures_declared(self) -> List[str]:
 623        """
 624        Return the signatures of the public/eterxnal functions/state variables that are declared by this contract
 625        :return: list(string) the signatures of all the functions that can be called and are declared by this contract
 626        """
 627        if self._signatures_declared is None:
 628            sigs = [
 629                v.full_name
 630                for v in self.state_variables_declared
 631                if v.visibility in ["public", "external"]
 632            ]
 633
 634            sigs += {
 635                f.full_name
 636                for f in self.functions_declared
 637                if f.visibility in ["public", "external"]
 638            }
 639            self._signatures_declared = list(set(sigs))
 640        return self._signatures_declared
 641
 642    @property
 643    def functions(self) -> List["FunctionContract"]:
 644        """
 645        list(Function): List of the functions
 646        """
 647        return list(self._functions.values())
 648
 649    def available_functions_as_dict(self) -> Dict[str, "Function"]:
 650        if self._available_functions_as_dict is None:
 651            self._available_functions_as_dict = {
 652                f.full_name: f for f in self._functions.values() if not f.is_shadowed
 653            }
 654        return self._available_functions_as_dict
 655
 656    def add_function(self, func: "FunctionContract") -> None:
 657        self._functions[func.canonical_name] = func
 658
 659    def set_functions(self, functions: Dict[str, "FunctionContract"]) -> None:
 660        """
 661        Set the functions
 662
 663        :param functions:  dict full_name -> function
 664        :return:
 665        """
 666        self._functions = functions
 667
 668    @property
 669    def functions_inherited(self) -> List["FunctionContract"]:
 670        """
 671        list(Function): List of the inherited functions
 672        """
 673        return [f for f in self.functions if f.contract_declarer != self]
 674
 675    @property
 676    def functions_declared(self) -> List["FunctionContract"]:
 677        """
 678        list(Function): List of the functions defined within the contract (not inherited)
 679        """
 680        return [f for f in self.functions if f.contract_declarer == self]
 681
 682    @property
 683    def functions_entry_points(self) -> List["FunctionContract"]:
 684        """
 685        list(Functions): List of public and external functions
 686        """
 687        return [
 688            f
 689            for f in self.functions
 690            if f.visibility in ["public", "external"] and not f.is_shadowed or f.is_fallback
 691        ]
 692
 693    @property
 694    def modifiers(self) -> List["Modifier"]:
 695        """
 696        list(Modifier): List of the modifiers
 697        """
 698        return list(self._modifiers.values())
 699
 700    def available_modifiers_as_dict(self) -> Dict[str, "Modifier"]:
 701        return {m.full_name: m for m in self._modifiers.values() if not m.is_shadowed}
 702
 703    def set_modifiers(self, modifiers: Dict[str, "Modifier"]) -> None:
 704        """
 705        Set the modifiers
 706
 707        :param modifiers:  dict full_name -> modifier
 708        :return:
 709        """
 710        self._modifiers = modifiers
 711
 712    @property
 713    def modifiers_inherited(self) -> List["Modifier"]:
 714        """
 715        list(Modifier): List of the inherited modifiers
 716        """
 717        return [m for m in self.modifiers if m.contract_declarer != self]
 718
 719    @property
 720    def modifiers_declared(self) -> List["Modifier"]:
 721        """
 722        list(Modifier): List of the modifiers defined within the contract (not inherited)
 723        """
 724        return [m for m in self.modifiers if m.contract_declarer == self]
 725
 726    @property
 727    def functions_and_modifiers(self) -> List["Function"]:
 728        """
 729        list(Function|Modifier): List of the functions and modifiers
 730        """
 731        return self.functions + self.modifiers  # type: ignore
 732
 733    @property
 734    def functions_and_modifiers_inherited(self) -> List["Function"]:
 735        """
 736        list(Function|Modifier): List of the inherited functions and modifiers
 737        """
 738        return self.functions_inherited + self.modifiers_inherited  # type: ignore
 739
 740    @property
 741    def functions_and_modifiers_declared(self) -> List["Function"]:
 742        """
 743        list(Function|Modifier): List of the functions and modifiers defined within the contract (not inherited)
 744        """
 745        return self.functions_declared + self.modifiers_declared  # type: ignore
 746
 747    @property
 748    def fallback_function(self) -> Optional["FunctionContract"]:
 749        if self._fallback_function is None:
 750            for f in self.functions:
 751                if f.is_fallback:
 752                    self._fallback_function = f
 753                    break
 754        return self._fallback_function
 755
 756    @property
 757    def receive_function(self) -> Optional["FunctionContract"]:
 758        if self._receive_function is None:
 759            for f in self.functions:
 760                if f.is_receive:
 761                    self._receive_function = f
 762                    break
 763        return self._receive_function
 764
 765    def available_elements_from_inheritances(
 766        self,
 767        elements: Dict[str, "Function"],
 768        getter_available: Callable[["Contract"], List["FunctionContract"]],
 769    ) -> Dict[str, "Function"]:
 770        """
 771
 772        :param elements: dict(canonical_name -> elements)
 773        :param getter_available: fun x
 774        :return:
 775        """
 776        # keep track of the contracts visited
 777        # to prevent an ovveride due to multiple inheritance of the same contract
 778        # A is B, C, D is C, --> the second C was already seen
 779        inherited_elements: Dict[str, "FunctionContract"] = {}
 780        accessible_elements = {}
 781        contracts_visited = []
 782        for father in self.inheritance_reverse:
 783            functions: Dict[str, "FunctionContract"] = {
 784                v.full_name: v
 785                for v in getter_available(father)
 786                if v.contract not in contracts_visited
 787                and v.function_language
 788                != FunctionLanguage.Yul  # Yul functions are not propagated in the inheritance
 789            }
 790            contracts_visited.append(father)
 791            inherited_elements.update(functions)
 792
 793        for element in inherited_elements.values():
 794            accessible_elements[element.full_name] = elements[element.canonical_name]
 795
 796        return accessible_elements
 797
 798    # endregion
 799    ###################################################################################
 800    ###################################################################################
 801    # region Inheritance
 802    ###################################################################################
 803    ###################################################################################
 804
 805    @property
 806    def inheritance(self) -> List["Contract"]:
 807        """
 808        list(Contract): Inheritance list. Order: the first elem is the first father to be executed
 809        """
 810        return list(self._inheritance)
 811
 812    @property
 813    def immediate_inheritance(self) -> List["Contract"]:
 814        """
 815        list(Contract): List of contracts immediately inherited from (fathers). Order: order of declaration.
 816        """
 817        return list(self._immediate_inheritance)
 818
 819    @property
 820    def inheritance_reverse(self) -> List["Contract"]:
 821        """
 822        list(Contract): Inheritance list. Order: the last elem is the first father to be executed
 823        """
 824        return list(reversed(self._inheritance))
 825
 826    def set_inheritance(
 827        self,
 828        inheritance: List["Contract"],
 829        immediate_inheritance: List["Contract"],
 830        called_base_constructor_contracts: List["Contract"],
 831    ) -> None:
 832        self._inheritance = inheritance
 833        self._immediate_inheritance = immediate_inheritance
 834        self._explicit_base_constructor_calls = called_base_constructor_contracts
 835
 836    @property
 837    def derived_contracts(self) -> List["Contract"]:
 838        """
 839        list(Contract): Return the list of contracts derived from self
 840        """
 841        candidates = self.compilation_unit.contracts
 842        return [c for c in candidates if self in c.inheritance]  # type: ignore
 843
 844    # endregion
 845    ###################################################################################
 846    ###################################################################################
 847    # region Getters from/to object
 848    ###################################################################################
 849    ###################################################################################
 850
 851    def get_functions_reading_from_variable(self, variable: "Variable") -> List["Function"]:
 852        """
 853        Return the functions reading the variable
 854        """
 855        return [f for f in self.functions if f.is_reading(variable)]
 856
 857    def get_functions_writing_to_variable(self, variable: "Variable") -> List["Function"]:
 858        """
 859        Return the functions writting the variable
 860        """
 861        return [f for f in self.functions if f.is_writing(variable)]
 862
 863    def get_function_from_full_name(self, full_name: str) -> Optional["Function"]:
 864        """
 865            Return a function from a full name
 866            The full name differs from the solidity's signature are the type are conserved
 867            For example contract type are kept, structure are not unrolled, etc
 868        Args:
 869            full_name (str): signature of the function (without return statement)
 870        Returns:
 871            Function
 872        """
 873        return next(
 874            (f for f in self.functions if f.full_name == full_name and not f.is_shadowed),
 875            None,
 876        )
 877
 878    def get_function_from_signature(self, function_signature: str) -> Optional["Function"]:
 879        """
 880            Return a function from a signature
 881        Args:
 882            function_signature (str): signature of the function (without return statement)
 883        Returns:
 884            Function
 885        """
 886        return next(
 887            (
 888                f
 889                for f in self.functions
 890                if f.solidity_signature == function_signature and not f.is_shadowed
 891            ),
 892            None,
 893        )
 894
 895    def get_modifier_from_signature(self, modifier_signature: str) -> Optional["Modifier"]:
 896        """
 897        Return a modifier from a signature
 898
 899        :param modifier_signature:
 900        """
 901        return next(
 902            (m for m in self.modifiers if m.full_name == modifier_signature and not m.is_shadowed),
 903            None,
 904        )
 905
 906    def get_function_from_canonical_name(self, canonical_name: str) -> Optional["Function"]:
 907        """
 908            Return a function from a canonical name (contract.signature())
 909        Args:
 910            canonical_name (str): canonical name of the function (without return statement)
 911        Returns:
 912            Function
 913        """
 914        return next((f for f in self.functions if f.canonical_name == canonical_name), None)
 915
 916    def get_modifier_from_canonical_name(self, canonical_name: str) -> Optional["Modifier"]:
 917        """
 918            Return a modifier from a canonical name (contract.signature())
 919        Args:
 920            canonical_name (str): canonical name of the modifier
 921        Returns:
 922            Modifier
 923        """
 924        return next((m for m in self.modifiers if m.canonical_name == canonical_name), None)
 925
 926    def get_state_variable_from_name(self, variable_name: str) -> Optional["StateVariable"]:
 927        """
 928        Return a state variable from a name
 929
 930        :param variable_name:
 931        """
 932        return next((v for v in self.state_variables if v.name == variable_name), None)
 933
 934    def get_state_variable_from_canonical_name(
 935        self, canonical_name: str
 936    ) -> Optional["StateVariable"]:
 937        """
 938            Return a state variable from a canonical_name
 939        Args:
 940            canonical_name (str): name of the variable
 941        Returns:
 942            StateVariable
 943        """
 944        return next((v for v in self.state_variables if v.canonical_name == canonical_name), None)
 945
 946    def get_structure_from_name(self, structure_name: str) -> Optional["StructureContract"]:
 947        """
 948            Return a structure from a name
 949        Args:
 950            structure_name (str): name of the structure
 951        Returns:
 952            StructureContract
 953        """
 954        return next((st for st in self.structures if st.name == structure_name), None)
 955
 956    def get_structure_from_canonical_name(
 957        self, structure_name: str
 958    ) -> Optional["StructureContract"]:
 959        """
 960            Return a structure from a canonical name
 961        Args:
 962            structure_name (str): canonical name of the structure
 963        Returns:
 964            StructureContract
 965        """
 966        return next((st for st in self.structures if st.canonical_name == structure_name), None)
 967
 968    def get_event_from_signature(self, event_signature: str) -> Optional["Event"]:
 969        """
 970            Return an event from a signature
 971        Args:
 972            event_signature (str): signature of the event
 973        Returns:
 974            Event
 975        """
 976        return next((e for e in self.events if e.full_name == event_signature), None)
 977
 978    def get_event_from_canonical_name(self, event_canonical_name: str) -> Optional["Event"]:
 979        """
 980            Return an event from a canonical name
 981        Args:
 982            event_canonical_name (str): name of the event
 983        Returns:
 984            Event
 985        """
 986        return next((e for e in self.events if e.canonical_name == event_canonical_name), None)
 987
 988    def get_enum_from_name(self, enum_name: str) -> Optional["Enum"]:
 989        """
 990            Return an enum from a name
 991        Args:
 992            enum_name (str): name of the enum
 993        Returns:
 994            Enum
 995        """
 996        return next((e for e in self.enums if e.name == enum_name), None)
 997
 998    def get_enum_from_canonical_name(self, enum_name: str) -> Optional["Enum"]:
 999        """
1000            Return an enum from a canonical name
1001        Args:
1002            enum_name (str): canonical name of the enum
1003        Returns:
1004            Enum
1005        """
1006        return next((e for e in self.enums if e.canonical_name == enum_name), None)
1007
1008    def get_functions_overridden_by(self, function: "Function") -> List["Function"]:
1009        """
1010            Return the list of functions overridden by the function
1011        Args:
1012            (core.Function)
1013        Returns:
1014            list(core.Function)
1015
1016        """
1017        return function.overrides
1018
1019    # endregion
1020    ###################################################################################
1021    ###################################################################################
1022    # region Recursive getters
1023    ###################################################################################
1024    ###################################################################################
1025
1026    @property
1027    def all_functions_called(self) -> List["InternalCallType"]:
1028        """
1029        list(Function): List of functions reachable from the contract
1030        Includes super, and private/internal functions not shadowed
1031        """
1032        if self._all_functions_called is None:
1033            all_functions = [f for f in self.functions + self.modifiers if not f.is_shadowed]  # type: ignore
1034            all_callss = [f.all_internal_calls() for f in all_functions] + [list(all_functions)]
1035            all_calls = [item for sublist in all_callss for item in sublist]
1036            all_calls = list(set(all_calls))
1037
1038            all_constructors = [c.constructor for c in self.inheritance if c.constructor]
1039            all_constructors = list(set(all_constructors))
1040
1041            set_all_calls = set(all_calls + list(all_constructors))
1042
1043            self._all_functions_called = [c for c in set_all_calls if isinstance(c, Function)]
1044        return self._all_functions_called
1045
1046    @property
1047    def all_state_variables_written(self) -> List["StateVariable"]:
1048        """
1049        list(StateVariable): List all of the state variables written
1050        """
1051        all_state_variables_writtens = [
1052            f.all_state_variables_written() for f in self.functions + self.modifiers  # type: ignore
1053        ]
1054        all_state_variables_written = [
1055            item for sublist in all_state_variables_writtens for item in sublist
1056        ]
1057        return list(set(all_state_variables_written))
1058
1059    @property
1060    def all_state_variables_read(self) -> List["StateVariable"]:
1061        """
1062        list(StateVariable): List all of the state variables read
1063        """
1064        all_state_variables_reads = [
1065            f.all_state_variables_read() for f in self.functions + self.modifiers  # type: ignore
1066        ]
1067        all_state_variables_read = [
1068            item for sublist in all_state_variables_reads for item in sublist
1069        ]
1070        return list(set(all_state_variables_read))
1071
1072    @property
1073    def all_library_calls(self) -> List["LibraryCallType"]:
1074        """
1075        list((Contract, Function): List all of the libraries func called
1076        """
1077        all_high_level_callss = [f.all_library_calls() for f in self.functions + self.modifiers]  # type: ignore
1078        all_high_level_calls = [item for sublist in all_high_level_callss for item in sublist]
1079        return list(set(all_high_level_calls))
1080
1081    @property
1082    def all_high_level_calls(self) -> List["HighLevelCallType"]:
1083        """
1084        list((Contract, Function|Variable)): List all of the external high level calls
1085        """
1086        all_high_level_callss = [f.all_high_level_calls() for f in self.functions + self.modifiers]  # type: ignore
1087        all_high_level_calls = [item for sublist in all_high_level_callss for item in sublist]
1088        return list(set(all_high_level_calls))
1089
1090    # endregion
1091    ###################################################################################
1092    ###################################################################################
1093    # region Summary information
1094    ###################################################################################
1095    ###################################################################################
1096
1097    def get_summary(
1098        self, include_shadowed: bool = True
1099    ) -> Tuple[str, List[str], List[str], List, List]:
1100        """Return the function summary
1101
1102        :param include_shadowed: boolean to indicate if shadowed functions should be included (default True)
1103        Returns:
1104            (str, list, list, list, list): (name, inheritance, variables, fuction summaries, modifier summaries)
1105        """
1106        func_summaries = [
1107            f.get_summary() for f in self.functions if (not f.is_shadowed or include_shadowed)
1108        ]
1109        modif_summaries = [
1110            f.get_summary() for f in self.modifiers if (not f.is_shadowed or include_shadowed)
1111        ]
1112        return (
1113            self.name,
1114            [str(x) for x in self.inheritance],
1115            [str(x) for x in self.variables],
1116            func_summaries,
1117            modif_summaries,
1118        )
1119
1120    def is_signature_only(self) -> bool:
1121        """Detect if the contract has only abstract functions
1122
1123        Returns:
1124            bool: true if the function are abstract functions
1125        """
1126        return all((not f.is_implemented) for f in self.functions)
1127
1128    # endregion
1129    ###################################################################################
1130    ###################################################################################
1131    # region ERC conformance
1132    ###################################################################################
1133    ###################################################################################
1134
1135    def ercs(self) -> List[str]:
1136        """
1137        Return the ERC implemented
1138        :return: list of string
1139        """
1140        all_erc = [
1141            ("ERC20", self.is_erc20),
1142            ("ERC165", self.is_erc165),
1143            ("ERC1820", self.is_erc1820),
1144            ("ERC223", self.is_erc223),
1145            ("ERC721", self.is_erc721),
1146            ("ERC777", self.is_erc777),
1147            ("ERC2612", self.is_erc2612),
1148            ("ERC1363", self.is_erc1363),
1149            ("ERC4626", self.is_erc4626),
1150        ]
1151
1152        return [erc for erc, is_erc in all_erc if is_erc()]
1153
1154    def is_erc20(self) -> bool:
1155        """
1156            Check if the contract is an erc20 token
1157
1158            Note: it does not check for correct return values
1159        :return: Returns a true if the contract is an erc20
1160        """
1161        full_names = self.functions_signatures
1162        return all(s in full_names for s in ERC20_signatures)
1163
1164    def is_erc165(self) -> bool:
1165        """
1166            Check if the contract is an erc165 token
1167
1168            Note: it does not check for correct return values
1169        :return: Returns a true if the contract is an erc165
1170        """
1171        full_names = self.functions_signatures
1172        return all(s in full_names for s in ERC165_signatures)
1173
1174    def is_erc1820(self) -> bool:
1175        """
1176            Check if the contract is an erc1820
1177
1178            Note: it does not check for correct return values
1179        :return: Returns a true if the contract is an erc165
1180        """
1181        full_names = self.functions_signatures
1182        return all(s in full_names for s in ERC1820_signatures)
1183
1184    def is_erc223(self) -> bool:
1185        """
1186            Check if the contract is an erc223 token
1187
1188            Note: it does not check for correct return values
1189        :return: Returns a true if the contract is an erc223
1190        """
1191        full_names = self.functions_signatures
1192        return all(s in full_names for s in ERC223_signatures)
1193
1194    def is_erc721(self) -> bool:
1195        """
1196            Check if the contract is an erc721 token
1197
1198            Note: it does not check for correct return values
1199        :return: Returns a true if the contract is an erc721
1200        """
1201        full_names = self.functions_signatures
1202        return all(s in full_names for s in ERC721_signatures)
1203
1204    def is_erc777(self) -> bool:
1205        """
1206            Check if the contract is an erc777
1207
1208            Note: it does not check for correct return values
1209        :return: Returns a true if the contract is an erc165
1210        """
1211        full_names = self.functions_signatures
1212        return all(s in full_names for s in ERC777_signatures)
1213
1214    def is_erc1155(self) -> bool:
1215        """
1216            Check if the contract is an erc1155
1217
1218            Note: it does not check for correct return values
1219        :return: Returns a true if the contract is an erc1155
1220        """
1221        full_names = self.functions_signatures
1222        return all(s in full_names for s in ERC1155_signatures)
1223
1224    def is_erc4626(self) -> bool:
1225        """
1226            Check if the contract is an erc4626
1227
1228            Note: it does not check for correct return values
1229        :return: Returns a true if the contract is an erc4626
1230        """
1231        full_names = self.functions_signatures
1232        return all(s in full_names for s in ERC4626_signatures)
1233
1234    def is_erc2612(self) -> bool:
1235        """
1236            Check if the contract is an erc2612
1237
1238            Note: it does not check for correct return values
1239        :return: Returns a true if the contract is an erc2612
1240        """
1241        full_names = self.functions_signatures
1242        return all(s in full_names for s in ERC2612_signatures)
1243
1244    def is_erc1363(self) -> bool:
1245        """
1246            Check if the contract is an erc1363
1247
1248            Note: it does not check for correct return values
1249        :return: Returns a true if the contract is an erc1363
1250        """
1251        full_names = self.functions_signatures
1252        return all(s in full_names for s in ERC1363_signatures)
1253
1254    def is_erc4524(self) -> bool:
1255        """
1256            Check if the contract is an erc4524
1257
1258            Note: it does not check for correct return values
1259        :return: Returns a true if the contract is an erc4524
1260        """
1261        full_names = self.functions_signatures
1262        return all(s in full_names for s in ERC4524_signatures)
1263
1264    @property
1265    def is_token(self) -> bool:
1266        """
1267        Check if the contract follows one of the standard ERC token
1268        :return:
1269        """
1270        return (
1271            self.is_erc20()
1272            or self.is_erc721()
1273            or self.is_erc165()
1274            or self.is_erc223()
1275            or self.is_erc777()
1276            or self.is_erc1155()
1277        )
1278
1279    def is_possible_erc20(self) -> bool:
1280        """
1281        Checks if the provided contract could be attempting to implement ERC20 standards.
1282
1283        :return: Returns a boolean indicating if the provided contract met the token standard.
1284        """
1285        # We do not check for all the functions, as name(), symbol(), might give too many FPs
1286        full_names = self.functions_signatures
1287        return (
1288            "transfer(address,uint256)" in full_names
1289            or "transferFrom(address,address,uint256)" in full_names
1290            or "approve(address,uint256)" in full_names
1291        )
1292
1293    def is_possible_erc721(self) -> bool:
1294        """
1295        Checks if the provided contract could be attempting to implement ERC721 standards.
1296
1297        :return: Returns a boolean indicating if the provided contract met the token standard.
1298        """
1299        # We do not check for all the functions, as name(), symbol(), might give too many FPs
1300        full_names = self.functions_signatures
1301        return (
1302            "ownerOf(uint256)" in full_names
1303            or "safeTransferFrom(address,address,uint256,bytes)" in full_names
1304            or "safeTransferFrom(address,address,uint256)" in full_names
1305            or "setApprovalForAll(address,bool)" in full_names
1306            or "getApproved(uint256)" in full_names
1307            or "isApprovedForAll(address,address)" in full_names
1308        )
1309
1310    @property
1311    def is_possible_token(self) -> bool:
1312        """
1313        Check if the contract is a potential token (it might not implement all the functions)
1314        :return:
1315        """
1316        return self.is_possible_erc20() or self.is_possible_erc721()
1317
1318    # endregion
1319    ###################################################################################
1320    ###################################################################################
1321    # region Dependencies
1322    ###################################################################################
1323    ###################################################################################
1324
1325    def is_from_dependency(self) -> bool:
1326        return self.compilation_unit.core.crytic_compile.is_dependency(
1327            self.source_mapping.filename.absolute
1328        )
1329
1330    # endregion
1331    ###################################################################################
1332    ###################################################################################
1333    # region Test
1334    ###################################################################################
1335    ###################################################################################
1336
1337    @property
1338    def is_truffle_migration(self) -> bool:
1339        """
1340        Return true if the contract is the Migrations contract needed for Truffle
1341        :return:
1342        """
1343        if self.compilation_unit.core.crytic_compile.platform == PlatformType.TRUFFLE:
1344            if self.name == "Migrations":
1345                paths = Path(self.source_mapping.filename.absolute).parts
1346                if len(paths) >= 2:
1347                    return paths[-2] == "contracts" and paths[-1] == "migrations.sol"
1348        return False
1349
1350    @property
1351    def is_test(self) -> bool:
1352        return is_test_contract(self) or self.is_truffle_migration  # type: ignore
1353
1354    # endregion
1355    ###################################################################################
1356    ###################################################################################
1357    # region Function analyses
1358    ###################################################################################
1359    ###################################################################################
1360
1361    def update_read_write_using_ssa(self) -> None:
1362        for function in self.functions + list(self.modifiers):
1363            function.update_read_write_using_ssa()
1364
1365    # endregion
1366    ###################################################################################
1367    ###################################################################################
1368    # region Upgradeability
1369    ###################################################################################
1370    ###################################################################################
1371
1372    @property
1373    def is_upgradeable(self) -> bool:
1374        if self._is_upgradeable is None:
1375            self._is_upgradeable = False
1376            initializable = self.file_scope.get_contract_from_name("Initializable")
1377            if initializable:
1378                if initializable in self.inheritance:
1379                    self._is_upgradeable = True
1380            else:
1381                for contract in self.inheritance + [self]:
1382                    # This might lead to false positive
1383                    # Not sure why pylint is having a trouble here
1384                    # pylint: disable=no-member
1385                    lower_name = contract.name.lower()
1386                    if "upgradeable" in lower_name or "upgradable" in lower_name:
1387                        self._is_upgradeable = True
1388                        break
1389                    if "initializable" in lower_name:
1390                        self._is_upgradeable = True
1391                        break
1392        return self._is_upgradeable
1393
1394    @is_upgradeable.setter
1395    def is_upgradeable(self, upgradeable: bool) -> None:
1396        self._is_upgradeable = upgradeable
1397
1398    @property
1399    def is_upgradeable_proxy(self) -> bool:
1400        from slither.core.cfg.node import NodeType
1401        from slither.slithir.operations import LowLevelCall
1402
1403        if self._is_upgradeable_proxy is None:
1404            self._is_upgradeable_proxy = False
1405            if "Proxy" in self.name:
1406                self._is_upgradeable_proxy = True
1407                return True
1408            for f in self.functions:
1409                if f.is_fallback:
1410                    for node in f.all_nodes():
1411                        for ir in node.irs:
1412                            if isinstance(ir, LowLevelCall) and ir.function_name == "delegatecall":
1413                                self._is_upgradeable_proxy = True
1414                                return self._is_upgradeable_proxy
1415                        if node.type == NodeType.ASSEMBLY:
1416                            inline_asm = node.inline_asm
1417                            if inline_asm:
1418                                if "delegatecall" in inline_asm:
1419                                    self._is_upgradeable_proxy = True
1420                                    return self._is_upgradeable_proxy
1421        return self._is_upgradeable_proxy
1422
1423    @is_upgradeable_proxy.setter
1424    def is_upgradeable_proxy(self, upgradeable_proxy: bool) -> None:
1425        self._is_upgradeable_proxy = upgradeable_proxy
1426
1427    @property
1428    def upgradeable_version(self) -> Optional[str]:
1429        return self._upgradeable_version
1430
1431    @upgradeable_version.setter
1432    def upgradeable_version(self, version_name: str) -> None:
1433        self._upgradeable_version = version_name
1434
1435    # endregion
1436    ###################################################################################
1437    ###################################################################################
1438    # region Internals
1439    ###################################################################################
1440    ###################################################################################
1441
1442    @property
1443    def is_incorrectly_constructed(self) -> bool:
1444        """
1445        Return true if there was an internal Slither's issue when analyzing the contract
1446        :return:
1447        """
1448        return self._is_incorrectly_parsed
1449
1450    @is_incorrectly_constructed.setter
1451    def is_incorrectly_constructed(self, incorrect: bool) -> None:
1452        self._is_incorrectly_parsed = incorrect
1453
1454    def add_constructor_variables(self) -> None:
1455        from slither.core.declarations.function_contract import FunctionContract
1456
1457        if self.state_variables:
1458            for (idx, variable_candidate) in enumerate(self.state_variables):
1459                if variable_candidate.expression and not variable_candidate.is_constant:
1460
1461                    constructor_variable = FunctionContract(self.compilation_unit)
1462                    constructor_variable.set_function_type(FunctionType.CONSTRUCTOR_VARIABLES)
1463                    constructor_variable.set_contract(self)  # type: ignore
1464                    constructor_variable.set_contract_declarer(self)  # type: ignore
1465                    constructor_variable.set_visibility("internal")
1466                    # For now, source mapping of the constructor variable is the whole contract
1467                    # Could be improved with a targeted source mapping
1468                    constructor_variable.set_offset(self.source_mapping, self.compilation_unit)
1469                    self._functions[constructor_variable.canonical_name] = constructor_variable
1470
1471                    prev_node = self._create_node(
1472                        constructor_variable, 0, variable_candidate, constructor_variable
1473                    )
1474                    variable_candidate.node_initialization = prev_node
1475                    counter = 1
1476                    for v in self.state_variables[idx + 1 :]:
1477                        if v.expression and not v.is_constant:
1478                            next_node = self._create_node(
1479                                constructor_variable, counter, v, prev_node.scope
1480                            )
1481                            v.node_initialization = next_node
1482                            prev_node.add_son(next_node)
1483                            next_node.add_father(prev_node)
1484                            prev_node = next_node
1485                            counter += 1
1486                    break
1487
1488            for (idx, variable_candidate) in enumerate(self.state_variables):
1489                if variable_candidate.expression and variable_candidate.is_constant:
1490
1491                    constructor_variable = FunctionContract(self.compilation_unit)
1492                    constructor_variable.set_function_type(
1493                        FunctionType.CONSTRUCTOR_CONSTANT_VARIABLES
1494                    )
1495                    constructor_variable.set_contract(self)  # type: ignore
1496                    constructor_variable.set_contract_declarer(self)  # type: ignore
1497                    constructor_variable.set_visibility("internal")
1498                    # For now, source mapping of the constructor variable is the whole contract
1499                    # Could be improved with a targeted source mapping
1500                    constructor_variable.set_offset(self.source_mapping, self.compilation_unit)
1501                    self._functions[constructor_variable.canonical_name] = constructor_variable
1502
1503                    prev_node = self._create_node(
1504                        constructor_variable, 0, variable_candidate, constructor_variable
1505                    )
1506                    variable_candidate.node_initialization = prev_node
1507                    counter = 1
1508                    for v in self.state_variables[idx + 1 :]:
1509                        if v.expression and v.is_constant:
1510                            next_node = self._create_node(
1511                                constructor_variable, counter, v, prev_node.scope
1512                            )
1513                            v.node_initialization = next_node
1514                            prev_node.add_son(next_node)
1515                            next_node.add_father(prev_node)
1516                            prev_node = next_node
1517                            counter += 1
1518
1519                    break
1520
1521    def _create_node(
1522        self, func: Function, counter: int, variable: "Variable", scope: Union[Scope, Function]
1523    ) -> "Node":
1524        from slither.core.cfg.node import Node, NodeType
1525        from slither.core.expressions import (
1526            AssignmentOperationType,
1527            AssignmentOperation,
1528            Identifier,
1529        )
1530
1531        # Function uses to create node for state variable declaration statements
1532        node = Node(NodeType.OTHER_ENTRYPOINT, counter, scope, func.file_scope)
1533        node.set_offset(variable.source_mapping, self.compilation_unit)
1534        node.set_function(func)
1535        func.add_node(node)
1536        assert variable.expression
1537        expression = AssignmentOperation(
1538            Identifier(variable),
1539            variable.expression,
1540            AssignmentOperationType.ASSIGN,
1541            variable.type,
1542        )
1543
1544        expression.set_offset(variable.source_mapping, self.compilation_unit)
1545        node.add_expression(expression)
1546        return node
1547
1548    # endregion
1549    ###################################################################################
1550    ###################################################################################
1551    # region SlithIR
1552    ###################################################################################
1553    ###################################################################################
1554
1555    def convert_expression_to_slithir_ssa(self) -> None:
1556        """
1557        Assume generate_slithir_and_analyze was called on all functions
1558
1559        :return:
1560        """
1561        from slither.slithir.variables import StateIRVariable
1562
1563        all_ssa_state_variables_instances = {}
1564
1565        for contract in self.inheritance:
1566            for v in contract.state_variables_declared:
1567                new_var = StateIRVariable(v)
1568                all_ssa_state_variables_instances[v.canonical_name] = new_var
1569                self._initial_state_variables.append(new_var)
1570
1571        for v in self.variables:
1572            if v.contract == self:
1573                new_var = StateIRVariable(v)
1574                all_ssa_state_variables_instances[v.canonical_name] = new_var
1575                self._initial_state_variables.append(new_var)
1576
1577        for func in self.functions + list(self.modifiers):
1578            func.generate_slithir_ssa(all_ssa_state_variables_instances)
1579
1580    def fix_phi(self) -> None:
1581        last_state_variables_instances: Dict[str, List["StateVariable"]] = {}
1582        initial_state_variables_instances: Dict[str, "StateVariable"] = {}
1583        for v in self._initial_state_variables:
1584            last_state_variables_instances[v.canonical_name] = []
1585            initial_state_variables_instances[v.canonical_name] = v
1586
1587        for func in self.functions + list(self.modifiers):
1588            result = func.get_last_ssa_state_variables_instances()
1589            for variable_name, instances in result.items():
1590                # TODO: investigate the next operation
1591                last_state_variables_instances[variable_name] += list(instances)
1592
1593        for func in self.functions + list(self.modifiers):
1594            func.fix_phi(last_state_variables_instances, initial_state_variables_instances)
1595
1596    # endregion
1597    ###################################################################################
1598    ###################################################################################
1599    # region Built in definitions
1600    ###################################################################################
1601    ###################################################################################
1602
1603    def __eq__(self, other: Any) -> bool:
1604        if isinstance(other, str):
1605            return other == self.name
1606        return NotImplemented
1607
1608    def __neq__(self, other: Any) -> bool:
1609        if isinstance(other, str):
1610            return other != self.name
1611        return NotImplemented
1612
1613    def __str__(self) -> str:
1614        return self.name
1615
1616    def __hash__(self) -> int:
1617        return self._id  # type:ignore
1618
1619    # endregion

Contract class

 59    def __init__(self, compilation_unit: "SlitherCompilationUnit", scope: "FileScope") -> None:
 60        super().__init__()
 61
 62        self._name: Optional[str] = None
 63        self._id: Optional[int] = None
 64        self._inheritance: List["Contract"] = []  # all contract inherited, c3 linearization
 65        self._immediate_inheritance: List["Contract"] = []  # immediate inheritance
 66
 67        # Constructors called on contract's definition
 68        # contract B is A(1) { ..
 69        self._explicit_base_constructor_calls: List["Contract"] = []
 70
 71        self._enums: Dict[str, "EnumContract"] = {}
 72        self._structures: Dict[str, "StructureContract"] = {}
 73        self._events: Dict[str, "EventContract"] = {}
 74        # map accessible variable from name -> variable
 75        # do not contain private variables inherited from contract
 76        self._variables: Dict[str, "StateVariable"] = {}
 77        self._variables_ordered: List["StateVariable"] = []
 78        # Reference id -> variable declaration (only available for compact AST)
 79        self._state_variables_by_ref_id: Dict[int, "StateVariable"] = {}
 80        self._modifiers: Dict[str, "Modifier"] = {}
 81        self._functions: Dict[str, "FunctionContract"] = {}
 82        self._linearizedBaseContracts: List[int] = []
 83        self._custom_errors: Dict[str, "CustomErrorContract"] = {}
 84        self._type_aliases: Dict[str, "TypeAliasContract"] = {}
 85
 86        # The only str is "*"
 87        self._using_for: USING_FOR = {}
 88        self._using_for_complete: Optional[USING_FOR] = None
 89        self._kind: Optional[str] = None
 90        self._is_interface: bool = False
 91        self._is_library: bool = False
 92        self._is_fully_implemented: bool = False
 93        self._is_abstract: bool = False
 94
 95        self._signatures: Optional[List[str]] = None
 96        self._signatures_declared: Optional[List[str]] = None
 97
 98        self._fallback_function: Optional["FunctionContract"] = None
 99        self._receive_function: Optional["FunctionContract"] = None
100
101        self._is_upgradeable: Optional[bool] = None
102        self._is_upgradeable_proxy: Optional[bool] = None
103        self._upgradeable_version: Optional[str] = None
104
105        self._initial_state_variables: List["StateVariable"] = []  # ssa
106
107        self._is_incorrectly_parsed: bool = False
108
109        self._available_functions_as_dict: Optional[Dict[str, "Function"]] = None
110        self._all_functions_called: Optional[List["InternalCallType"]] = None
111
112        self.compilation_unit: "SlitherCompilationUnit" = compilation_unit
113        self.file_scope: "FileScope" = scope
114
115        # memoize
116        self._state_variables_used_in_reentrant_targets: Optional[
117            Dict["StateVariable", Set[Union["StateVariable", "Function"]]]
118        ] = None
119
120        self._comments: Optional[str] = None
name: str
128    @property
129    def name(self) -> str:
130        """str: Name of the contract."""
131        assert self._name
132        return self._name

str: Name of the contract.

id: int
138    @property
139    def id(self) -> int:
140        """Unique id."""
141        assert self._id is not None
142        return self._id

Unique id.

contract_kind: Union[str, NoneType]
149    @property
150    def contract_kind(self) -> Optional[str]:
151        """
152        contract_kind can be None if the legacy ast format is used
153        :return:
154        """
155        return self._kind

contract_kind can be None if the legacy ast format is used

Returns
is_interface: bool
161    @property
162    def is_interface(self) -> bool:
163        return self._is_interface
is_library: bool
169    @property
170    def is_library(self) -> bool:
171        return self._is_library
comments: Union[str, NoneType]
177    @property
178    def comments(self) -> Optional[str]:
179        """
180        Return the comments associated with the contract.
181
182        When using comments, avoid strict text matching, as the solc behavior might change.
183        For example, for old solc version, the first space after the * is not kept, i.e:
184
185          * @title Test Contract
186          * @dev Test comment
187
188        Returns
189        - " @title Test Contract\n @dev Test comment" for newest versions
190        - "@title Test Contract\n@dev Test comment" for older versions
191
192
193        Returns:
194            the comment as a string
195        """
196        return self._comments

Return the comments associated with the contract.

    When using comments, avoid strict text matching, as the solc behavior might change.
    For example, for old solc version, the first space after the * is not kept, i.e:

      * @title Test Contract
      * @dev Test comment

    Returns
    - " @title Test Contract

@dev Test comment" for newest versions - "@title Test Contract @dev Test comment" for older versions

    Returns:
        the comment as a string
is_fully_implemented: bool
202    @property
203    def is_fully_implemented(self) -> bool:
204        """
205        bool: True if the contract defines all functions.
206        In modern Solidity, virtual functions can lack an implementation.
207        Prior to Solidity 0.6.0, functions like the following would be not fully implemented:
208        ```solidity
209        contract ImplicitAbstract{
210            function f() public;
211        }
212        ```
213        """
214        return self._is_fully_implemented

bool: True if the contract defines all functions. In modern Solidity, virtual functions can lack an implementation. Prior to Solidity 0.6.0, functions like the following would be not fully implemented:

contract ImplicitAbstract{
    function f() public;
}
is_abstract: bool
220    @property
221    def is_abstract(self) -> bool:
222        """
223        Note for Solidity < 0.6.0 it will always be false
224        bool: True if the contract is abstract.
225        """
226        return self._is_abstract

Note for Solidity < 0.6.0 it will always be false bool: True if the contract is abstract.

239    @property
240    def structures(self) -> List["StructureContract"]:
241        """
242        list(Structure): List of the structures
243        """
244        return list(self._structures.values())

list(Structure): List of the structures

structures_inherited: list[slither.core.declarations.structure_contract.StructureContract]
246    @property
247    def structures_inherited(self) -> List["StructureContract"]:
248        """
249        list(Structure): List of the inherited structures
250        """
251        return [s for s in self.structures if s.contract != self]

list(Structure): List of the inherited structures

253    @property
254    def structures_declared(self) -> List["StructureContract"]:
255        """
256        list(Structues): List of the structures declared within the contract (not inherited)
257        """
258        return [s for s in self.structures if s.contract == self]

list(Structues): List of the structures declared within the contract (not inherited)

structures_as_dict: dict[str, slither.core.declarations.structure_contract.StructureContract]
260    @property
261    def structures_as_dict(self) -> Dict[str, "StructureContract"]:
262        return self._structures
271    @property
272    def enums(self) -> List["EnumContract"]:
273        return list(self._enums.values())
enums_inherited: list[slither.core.declarations.enum_contract.EnumContract]
275    @property
276    def enums_inherited(self) -> List["EnumContract"]:
277        """
278        list(Enum): List of the inherited enums
279        """
280        return [e for e in self.enums if e.contract != self]

list(Enum): List of the inherited enums

enums_declared: list[slither.core.declarations.enum_contract.EnumContract]
282    @property
283    def enums_declared(self) -> List["EnumContract"]:
284        """
285        list(Enum): List of the enums declared within the contract (not inherited)
286        """
287        return [e for e in self.enums if e.contract == self]

list(Enum): List of the enums declared within the contract (not inherited)

enums_as_dict: dict[str, slither.core.declarations.enum_contract.EnumContract]
289    @property
290    def enums_as_dict(self) -> Dict[str, "EnumContract"]:
291        return self._enums
300    @property
301    def events(self) -> List["EventContract"]:
302        """
303        list(Event): List of the events
304        """
305        return list(self._events.values())

list(Event): List of the events

events_inherited: list[slither.core.declarations.event_contract.EventContract]
307    @property
308    def events_inherited(self) -> List["EventContract"]:
309        """
310        list(Event): List of the inherited events
311        """
312        return [e for e in self.events if e.contract != self]

list(Event): List of the inherited events

events_declared: list[slither.core.declarations.event_contract.EventContract]
314    @property
315    def events_declared(self) -> List["EventContract"]:
316        """
317        list(Event): List of the events declared within the contract (not inherited)
318        """
319        return [e for e in self.events if e.contract == self]

list(Event): List of the events declared within the contract (not inherited)

events_as_dict: dict[str, slither.core.declarations.event_contract.EventContract]
321    @property
322    def events_as_dict(self) -> Dict[str, "EventContract"]:
323        return self._events
332    @property
333    def using_for(self) -> USING_FOR:
334        return self._using_for
336    @property
337    def using_for_complete(self) -> USING_FOR:
338        """
339        USING_FOR: Dict of merged local using for directive with top level directive
340        """
341
342        if self._using_for_complete is None:
343            result = self.using_for
344            top_level_using_for = self.file_scope.using_for_directives
345            for uftl in top_level_using_for:
346                result = merge_using_for(result, uftl.using_for)
347            self._using_for_complete = result
348        return self._using_for_complete

USING_FOR: Dict of merged local using for directive with top level directive

357    @property
358    def custom_errors(self) -> List["CustomErrorContract"]:
359        """
360        list(CustomErrorContract): List of the contract's custom errors
361        """
362        return list(self._custom_errors.values())

list(CustomErrorContract): List of the contract's custom errors

custom_errors_inherited: list[slither.core.declarations.custom_error_contract.CustomErrorContract]
364    @property
365    def custom_errors_inherited(self) -> List["CustomErrorContract"]:
366        """
367        list(CustomErrorContract): List of the inherited custom errors
368        """
369        return [s for s in self.custom_errors if s.contract != self]

list(CustomErrorContract): List of the inherited custom errors

371    @property
372    def custom_errors_declared(self) -> List["CustomErrorContract"]:
373        """
374        list(CustomErrorContract): List of the custom errors declared within the contract (not inherited)
375        """
376        return [s for s in self.custom_errors if s.contract == self]

list(CustomErrorContract): List of the custom errors declared within the contract (not inherited)

custom_errors_as_dict: dict[str, slither.core.declarations.custom_error_contract.CustomErrorContract]
378    @property
379    def custom_errors_as_dict(self) -> Dict[str, "CustomErrorContract"]:
380        return self._custom_errors
389    @property
390    def type_aliases(self) -> List["TypeAliasContract"]:
391        """
392        list(TypeAliasContract): List of the contract's custom errors
393        """
394        return list(self._type_aliases.values())

list(TypeAliasContract): List of the contract's custom errors

type_aliases_inherited: list[slither.core.solidity_types.type_alias.TypeAliasContract]
396    @property
397    def type_aliases_inherited(self) -> List["TypeAliasContract"]:
398        """
399        list(TypeAliasContract): List of the inherited custom errors
400        """
401        return [s for s in self.type_aliases if s.contract != self]

list(TypeAliasContract): List of the inherited custom errors

type_aliases_declared: list[slither.core.solidity_types.type_alias.TypeAliasContract]
403    @property
404    def type_aliases_declared(self) -> List["TypeAliasContract"]:
405        """
406        list(TypeAliasContract): List of the custom errors declared within the contract (not inherited)
407        """
408        return [s for s in self.type_aliases if s.contract == self]

list(TypeAliasContract): List of the custom errors declared within the contract (not inherited)

type_aliases_as_dict: dict[str, slither.core.solidity_types.type_alias.TypeAliasContract]
410    @property
411    def type_aliases_as_dict(self) -> Dict[str, "TypeAliasContract"]:
412        return self._type_aliases
state_variables_by_ref_id: dict[int, slither.core.variables.state_variable.StateVariable]
420    @property
421    def state_variables_by_ref_id(self) -> Dict[int, "StateVariable"]:
422        """
423        Returns the state variables by reference id (only available for compact AST).
424        """
425        return self._state_variables_by_ref_id

Returns the state variables by reference id (only available for compact AST).

427    @property
428    def variables(self) -> List["StateVariable"]:
429        """
430        Returns all the accessible variables (do not include private variable from inherited contract)
431
432        list(StateVariable): List of the state variables. Alias to self.state_variables.
433        """
434        return list(self.state_variables)

Returns all the accessible variables (do not include private variable from inherited contract)

list(StateVariable): List of the state variables. Alias to self.state_variables.

variables_as_dict: dict[str, slither.core.variables.state_variable.StateVariable]
436    @property
437    def variables_as_dict(self) -> Dict[str, "StateVariable"]:
438        return self._variables
state_variables: list[slither.core.variables.state_variable.StateVariable]
440    @property
441    def state_variables(self) -> List["StateVariable"]:
442        """
443        Returns all the accessible variables (do not include private variable from inherited contract).
444        Use state_variables_ordered for all the variables following the storage order
445
446        list(StateVariable): List of the state variables.
447        """
448        return list(self._variables.values())

Returns all the accessible variables (do not include private variable from inherited contract). Use state_variables_ordered for all the variables following the storage order

list(StateVariable): List of the state variables.

stored_state_variables: list[slither.core.variables.state_variable.StateVariable]
450    @property
451    def stored_state_variables(self) -> List["StateVariable"]:
452        """
453        Returns state variables with storage locations, excluding private variables from inherited contracts.
454        Use stored_state_variables_ordered to access variables with storage locations in their declaration order.
455
456        This implementation filters out state variables if they are constant or immutable. It will be
457        updated to accommodate any new non-storage keywords that might replace 'constant' and 'immutable' in the future.
458
459        Returns:
460            List[StateVariable]: A list of state variables with storage locations.
461        """
462        return [variable for variable in self.state_variables if variable.is_stored]

Returns state variables with storage locations, excluding private variables from inherited contracts. Use stored_state_variables_ordered to access variables with storage locations in their declaration order.

This implementation filters out state variables if they are constant or immutable. It will be updated to accommodate any new non-storage keywords that might replace 'constant' and 'immutable' in the future.

Returns: List[StateVariable]: A list of state variables with storage locations.

stored_state_variables_ordered: list[slither.core.variables.state_variable.StateVariable]
464    @property
465    def stored_state_variables_ordered(self) -> List["StateVariable"]:
466        """
467        list(StateVariable): List of the state variables with storage locations by order of declaration.
468
469        This implementation filters out state variables if they are constant or immutable. It will be
470        updated to accommodate any new non-storage keywords that might replace 'constant' and 'immutable' in the future.
471
472        Returns:
473            List[StateVariable]: A list of state variables with storage locations ordered by declaration.
474        """
475        return [variable for variable in self.state_variables_ordered if variable.is_stored]

list(StateVariable): List of the state variables with storage locations by order of declaration.

This implementation filters out state variables if they are constant or immutable. It will be updated to accommodate any new non-storage keywords that might replace 'constant' and 'immutable' in the future.

Returns: List[StateVariable]: A list of state variables with storage locations ordered by declaration.

state_variables_entry_points: list[slither.core.variables.state_variable.StateVariable]
477    @property
478    def state_variables_entry_points(self) -> List["StateVariable"]:
479        """
480        list(StateVariable): List of the state variables that are public.
481        """
482        return [var for var in self._variables.values() if var.visibility == "public"]

list(StateVariable): List of the state variables that are public.

state_variables_ordered: list[slither.core.variables.state_variable.StateVariable]
484    @property
485    def state_variables_ordered(self) -> List["StateVariable"]:
486        """
487        list(StateVariable): List of the state variables by order of declaration.
488        """
489        return list(self._variables_ordered)

list(StateVariable): List of the state variables by order of declaration.

def add_variables_ordered( self, new_vars: list[slither.core.variables.state_variable.StateVariable]) -> None:
491    def add_variables_ordered(self, new_vars: List["StateVariable"]) -> None:
492        self._variables_ordered += new_vars
state_variables_inherited: list[slither.core.variables.state_variable.StateVariable]
494    @property
495    def state_variables_inherited(self) -> List["StateVariable"]:
496        """
497        list(StateVariable): List of the inherited state variables
498        """
499        return [s for s in self.state_variables if s.contract != self]

list(StateVariable): List of the inherited state variables

state_variables_declared: list[slither.core.variables.state_variable.StateVariable]
501    @property
502    def state_variables_declared(self) -> List["StateVariable"]:
503        """
504        list(StateVariable): List of the state variables declared within the contract (not inherited)
505        """
506        return [s for s in self.state_variables if s.contract == self]

list(StateVariable): List of the state variables declared within the contract (not inherited)

slithir_variables: list[slither.slithir.variables.variable.SlithIRVariable]
508    @property
509    def slithir_variables(self) -> List["SlithIRVariable"]:
510        """
511        List all of the slithir variables (non SSA)
512        """
513        slithir_variabless = [f.slithir_variables for f in self.functions + self.modifiers]  # type: ignore
514        slithir_variables = [item for sublist in slithir_variabless for item in sublist]
515        return list(set(slithir_variables))

List all of the slithir variables (non SSA)

517    @property
518    def state_variables_used_in_reentrant_targets(
519        self,
520    ) -> Dict["StateVariable", Set[Union["StateVariable", "Function"]]]:
521        """
522        Returns the state variables used in reentrant targets. Heuristics:
523        - Variable used (read/write) in entry points that are reentrant
524        - State variables that are public
525
526        """
527        from slither.core.variables.state_variable import StateVariable
528
529        if self._state_variables_used_in_reentrant_targets is None:
530            reentrant_functions = [f for f in self.functions_entry_points if f.is_reentrant]
531            variables_used: Dict[
532                StateVariable, Set[Union[StateVariable, "Function"]]
533            ] = defaultdict(set)
534            for function in reentrant_functions:
535                for ir in function.all_slithir_operations():
536                    state_variables = [v for v in ir.used if isinstance(v, StateVariable)]
537                    for state_variable in state_variables:
538                        variables_used[state_variable].add(ir.node.function)
539            for variable in [v for v in self.state_variables if v.visibility == "public"]:
540                variables_used[variable].add(variable)
541            self._state_variables_used_in_reentrant_targets = variables_used
542        return self._state_variables_used_in_reentrant_targets

Returns the state variables used in reentrant targets. Heuristics:

  • Variable used (read/write) in entry points that are reentrant
  • State variables that are public
constructor: Union[slither.core.declarations.function.Function, NoneType]
551    @property
552    def constructor(self) -> Optional["Function"]:
553        """
554        Return the contract's immediate constructor.
555        If there is no immediate constructor, returns the first constructor
556        executed, following the c3 linearization
557        Return None if there is no constructor.
558        """
559        cst = self.constructors_declared
560        if cst:
561            return cst
562        for inherited_contract in self.inheritance:
563            cst = inherited_contract.constructors_declared
564            if cst:
565                return cst
566        return None

Return the contract's immediate constructor. If there is no immediate constructor, returns the first constructor executed, following the c3 linearization Return None if there is no constructor.

constructors_declared: Union[slither.core.declarations.function.Function, NoneType]
568    @property
569    def constructors_declared(self) -> Optional["Function"]:
570        return next(
571            (
572                func
573                for func in self.functions
574                if func.is_constructor and func.contract_declarer == self
575            ),
576            None,
577        )
579    @property
580    def constructors(self) -> List["FunctionContract"]:
581        """
582        Return the list of constructors (including inherited)
583        """
584        return [func for func in self.functions if func.is_constructor]

Return the list of constructors (including inherited)

explicit_base_constructor_calls: list[slither.core.declarations.function.Function]
586    @property
587    def explicit_base_constructor_calls(self) -> List["Function"]:
588        """
589        list(Function): List of the base constructors called explicitly by this contract definition.
590
591                        Base constructors called by any constructor definition will not be included.
592                        Base constructors implicitly called by the contract definition (without
593                        parenthesis) will not be included.
594
595                        On "contract B is A(){..}" it returns the constructor of A
596        """
597        return [c.constructor for c in self._explicit_base_constructor_calls if c.constructor]

list(Function): List of the base constructors called explicitly by this contract definition.

Base constructors called by any constructor definition will not be included. Base constructors implicitly called by the contract definition (without parenthesis) will not be included.

On "contract B is A(){..}" it returns the constructor of A

functions_signatures: List[str]
606    @property
607    def functions_signatures(self) -> List[str]:
608        """
609        Return the signatures of all the public/eterxnal functions/state variables
610        :return: list(string) the signatures of all the functions that can be called
611        """
612        if self._signatures is None:
613            sigs = [
614                v.full_name for v in self.state_variables if v.visibility in ["public", "external"]
615            ]
616
617            sigs += {f.full_name for f in self.functions if f.visibility in ["public", "external"]}
618            self._signatures = list(set(sigs))
619        return self._signatures

Return the signatures of all the public/eterxnal functions/state variables

Returns

list(string) the signatures of all the functions that can be called

functions_signatures_declared: List[str]
621    @property
622    def functions_signatures_declared(self) -> List[str]:
623        """
624        Return the signatures of the public/eterxnal functions/state variables that are declared by this contract
625        :return: list(string) the signatures of all the functions that can be called and are declared by this contract
626        """
627        if self._signatures_declared is None:
628            sigs = [
629                v.full_name
630                for v in self.state_variables_declared
631                if v.visibility in ["public", "external"]
632            ]
633
634            sigs += {
635                f.full_name
636                for f in self.functions_declared
637                if f.visibility in ["public", "external"]
638            }
639            self._signatures_declared = list(set(sigs))
640        return self._signatures_declared

Return the signatures of the public/eterxnal functions/state variables that are declared by this contract

Returns

list(string) the signatures of all the functions that can be called and are declared by this contract

642    @property
643    def functions(self) -> List["FunctionContract"]:
644        """
645        list(Function): List of the functions
646        """
647        return list(self._functions.values())

list(Function): List of the functions

def available_functions_as_dict(self) -> dict[str, slither.core.declarations.function.Function]:
649    def available_functions_as_dict(self) -> Dict[str, "Function"]:
650        if self._available_functions_as_dict is None:
651            self._available_functions_as_dict = {
652                f.full_name: f for f in self._functions.values() if not f.is_shadowed
653            }
654        return self._available_functions_as_dict
def add_function( self, func: slither.core.declarations.function_contract.FunctionContract) -> None:
656    def add_function(self, func: "FunctionContract") -> None:
657        self._functions[func.canonical_name] = func
def set_functions( self, functions: dict[str, slither.core.declarations.function_contract.FunctionContract]) -> None:
659    def set_functions(self, functions: Dict[str, "FunctionContract"]) -> None:
660        """
661        Set the functions
662
663        :param functions:  dict full_name -> function
664        :return:
665        """
666        self._functions = functions

Set the functions

Parameters
  • functions: dict full_name -> function
Returns
functions_inherited: list[slither.core.declarations.function_contract.FunctionContract]
668    @property
669    def functions_inherited(self) -> List["FunctionContract"]:
670        """
671        list(Function): List of the inherited functions
672        """
673        return [f for f in self.functions if f.contract_declarer != self]

list(Function): List of the inherited functions

functions_declared: list[slither.core.declarations.function_contract.FunctionContract]
675    @property
676    def functions_declared(self) -> List["FunctionContract"]:
677        """
678        list(Function): List of the functions defined within the contract (not inherited)
679        """
680        return [f for f in self.functions if f.contract_declarer == self]

list(Function): List of the functions defined within the contract (not inherited)

functions_entry_points: list[slither.core.declarations.function_contract.FunctionContract]
682    @property
683    def functions_entry_points(self) -> List["FunctionContract"]:
684        """
685        list(Functions): List of public and external functions
686        """
687        return [
688            f
689            for f in self.functions
690            if f.visibility in ["public", "external"] and not f.is_shadowed or f.is_fallback
691        ]

list(Functions): List of public and external functions

modifiers: list[slither.core.declarations.modifier.Modifier]
693    @property
694    def modifiers(self) -> List["Modifier"]:
695        """
696        list(Modifier): List of the modifiers
697        """
698        return list(self._modifiers.values())

list(Modifier): List of the modifiers

def available_modifiers_as_dict(self) -> dict[str, slither.core.declarations.modifier.Modifier]:
700    def available_modifiers_as_dict(self) -> Dict[str, "Modifier"]:
701        return {m.full_name: m for m in self._modifiers.values() if not m.is_shadowed}
def set_modifiers( self, modifiers: dict[str, slither.core.declarations.modifier.Modifier]) -> None:
703    def set_modifiers(self, modifiers: Dict[str, "Modifier"]) -> None:
704        """
705        Set the modifiers
706
707        :param modifiers:  dict full_name -> modifier
708        :return:
709        """
710        self._modifiers = modifiers

Set the modifiers

Parameters
  • modifiers: dict full_name -> modifier
Returns
modifiers_inherited: list[slither.core.declarations.modifier.Modifier]
712    @property
713    def modifiers_inherited(self) -> List["Modifier"]:
714        """
715        list(Modifier): List of the inherited modifiers
716        """
717        return [m for m in self.modifiers if m.contract_declarer != self]

list(Modifier): List of the inherited modifiers

modifiers_declared: list[slither.core.declarations.modifier.Modifier]
719    @property
720    def modifiers_declared(self) -> List["Modifier"]:
721        """
722        list(Modifier): List of the modifiers defined within the contract (not inherited)
723        """
724        return [m for m in self.modifiers if m.contract_declarer == self]

list(Modifier): List of the modifiers defined within the contract (not inherited)

functions_and_modifiers: list[slither.core.declarations.function.Function]
726    @property
727    def functions_and_modifiers(self) -> List["Function"]:
728        """
729        list(Function|Modifier): List of the functions and modifiers
730        """
731        return self.functions + self.modifiers  # type: ignore

list(Function|Modifier): List of the functions and modifiers

functions_and_modifiers_inherited: list[slither.core.declarations.function.Function]
733    @property
734    def functions_and_modifiers_inherited(self) -> List["Function"]:
735        """
736        list(Function|Modifier): List of the inherited functions and modifiers
737        """
738        return self.functions_inherited + self.modifiers_inherited  # type: ignore

list(Function|Modifier): List of the inherited functions and modifiers

functions_and_modifiers_declared: list[slither.core.declarations.function.Function]
740    @property
741    def functions_and_modifiers_declared(self) -> List["Function"]:
742        """
743        list(Function|Modifier): List of the functions and modifiers defined within the contract (not inherited)
744        """
745        return self.functions_declared + self.modifiers_declared  # type: ignore

list(Function|Modifier): List of the functions and modifiers defined within the contract (not inherited)

fallback_function: Union[slither.core.declarations.function_contract.FunctionContract, NoneType]
747    @property
748    def fallback_function(self) -> Optional["FunctionContract"]:
749        if self._fallback_function is None:
750            for f in self.functions:
751                if f.is_fallback:
752                    self._fallback_function = f
753                    break
754        return self._fallback_function
receive_function: Union[slither.core.declarations.function_contract.FunctionContract, NoneType]
756    @property
757    def receive_function(self) -> Optional["FunctionContract"]:
758        if self._receive_function is None:
759            for f in self.functions:
760                if f.is_receive:
761                    self._receive_function = f
762                    break
763        return self._receive_function
def available_elements_from_inheritances( self, elements: dict[str, slither.core.declarations.function.Function], getter_available: Callable[Contract, list[slither.core.declarations.function_contract.FunctionContract]]) -> dict[str, slither.core.declarations.function.Function]:
765    def available_elements_from_inheritances(
766        self,
767        elements: Dict[str, "Function"],
768        getter_available: Callable[["Contract"], List["FunctionContract"]],
769    ) -> Dict[str, "Function"]:
770        """
771
772        :param elements: dict(canonical_name -> elements)
773        :param getter_available: fun x
774        :return:
775        """
776        # keep track of the contracts visited
777        # to prevent an ovveride due to multiple inheritance of the same contract
778        # A is B, C, D is C, --> the second C was already seen
779        inherited_elements: Dict[str, "FunctionContract"] = {}
780        accessible_elements = {}
781        contracts_visited = []
782        for father in self.inheritance_reverse:
783            functions: Dict[str, "FunctionContract"] = {
784                v.full_name: v
785                for v in getter_available(father)
786                if v.contract not in contracts_visited
787                and v.function_language
788                != FunctionLanguage.Yul  # Yul functions are not propagated in the inheritance
789            }
790            contracts_visited.append(father)
791            inherited_elements.update(functions)
792
793        for element in inherited_elements.values():
794            accessible_elements[element.full_name] = elements[element.canonical_name]
795
796        return accessible_elements
Parameters
  • elements: dict(canonical_name -> elements)
  • getter_available: fun x
Returns
inheritance: list[Contract]
805    @property
806    def inheritance(self) -> List["Contract"]:
807        """
808        list(Contract): Inheritance list. Order: the first elem is the first father to be executed
809        """
810        return list(self._inheritance)

list(Contract): Inheritance list. Order: the first elem is the first father to be executed

immediate_inheritance: list[Contract]
812    @property
813    def immediate_inheritance(self) -> List["Contract"]:
814        """
815        list(Contract): List of contracts immediately inherited from (fathers). Order: order of declaration.
816        """
817        return list(self._immediate_inheritance)

list(Contract): List of contracts immediately inherited from (fathers). Order: order of declaration.

inheritance_reverse: list[Contract]
819    @property
820    def inheritance_reverse(self) -> List["Contract"]:
821        """
822        list(Contract): Inheritance list. Order: the last elem is the first father to be executed
823        """
824        return list(reversed(self._inheritance))

list(Contract): Inheritance list. Order: the last elem is the first father to be executed

def set_inheritance( self, inheritance: list[Contract], immediate_inheritance: list[Contract], called_base_constructor_contracts: list[Contract]) -> None:
826    def set_inheritance(
827        self,
828        inheritance: List["Contract"],
829        immediate_inheritance: List["Contract"],
830        called_base_constructor_contracts: List["Contract"],
831    ) -> None:
832        self._inheritance = inheritance
833        self._immediate_inheritance = immediate_inheritance
834        self._explicit_base_constructor_calls = called_base_constructor_contracts
derived_contracts: list[Contract]
836    @property
837    def derived_contracts(self) -> List["Contract"]:
838        """
839        list(Contract): Return the list of contracts derived from self
840        """
841        candidates = self.compilation_unit.contracts
842        return [c for c in candidates if self in c.inheritance]  # type: ignore

list(Contract): Return the list of contracts derived from self

def get_functions_reading_from_variable( self, variable: slither.core.variables.variable.Variable) -> list[slither.core.declarations.function.Function]:
851    def get_functions_reading_from_variable(self, variable: "Variable") -> List["Function"]:
852        """
853        Return the functions reading the variable
854        """
855        return [f for f in self.functions if f.is_reading(variable)]

Return the functions reading the variable

def get_functions_writing_to_variable( self, variable: slither.core.variables.variable.Variable) -> list[slither.core.declarations.function.Function]:
857    def get_functions_writing_to_variable(self, variable: "Variable") -> List["Function"]:
858        """
859        Return the functions writting the variable
860        """
861        return [f for f in self.functions if f.is_writing(variable)]

Return the functions writting the variable

def get_function_from_full_name( self, full_name: str) -> Union[slither.core.declarations.function.Function, NoneType]:
863    def get_function_from_full_name(self, full_name: str) -> Optional["Function"]:
864        """
865            Return a function from a full name
866            The full name differs from the solidity's signature are the type are conserved
867            For example contract type are kept, structure are not unrolled, etc
868        Args:
869            full_name (str): signature of the function (without return statement)
870        Returns:
871            Function
872        """
873        return next(
874            (f for f in self.functions if f.full_name == full_name and not f.is_shadowed),
875            None,
876        )

Return a function from a full name The full name differs from the solidity's signature are the type are conserved For example contract type are kept, structure are not unrolled, etc Args: full_name (str): signature of the function (without return statement) Returns: Function

def get_function_from_signature( self, function_signature: str) -> Union[slither.core.declarations.function.Function, NoneType]:
878    def get_function_from_signature(self, function_signature: str) -> Optional["Function"]:
879        """
880            Return a function from a signature
881        Args:
882            function_signature (str): signature of the function (without return statement)
883        Returns:
884            Function
885        """
886        return next(
887            (
888                f
889                for f in self.functions
890                if f.solidity_signature == function_signature and not f.is_shadowed
891            ),
892            None,
893        )

Return a function from a signature Args: function_signature (str): signature of the function (without return statement) Returns: Function

def get_modifier_from_signature( self, modifier_signature: str) -> Union[slither.core.declarations.modifier.Modifier, NoneType]:
895    def get_modifier_from_signature(self, modifier_signature: str) -> Optional["Modifier"]:
896        """
897        Return a modifier from a signature
898
899        :param modifier_signature:
900        """
901        return next(
902            (m for m in self.modifiers if m.full_name == modifier_signature and not m.is_shadowed),
903            None,
904        )

Return a modifier from a signature

Parameters
  • modifier_signature:
def get_function_from_canonical_name( self, canonical_name: str) -> Union[slither.core.declarations.function.Function, NoneType]:
906    def get_function_from_canonical_name(self, canonical_name: str) -> Optional["Function"]:
907        """
908            Return a function from a canonical name (contract.signature())
909        Args:
910            canonical_name (str): canonical name of the function (without return statement)
911        Returns:
912            Function
913        """
914        return next((f for f in self.functions if f.canonical_name == canonical_name), None)

Return a function from a canonical name (contract.signature()) Args: canonical_name (str): canonical name of the function (without return statement) Returns: Function

def get_modifier_from_canonical_name( self, canonical_name: str) -> Union[slither.core.declarations.modifier.Modifier, NoneType]:
916    def get_modifier_from_canonical_name(self, canonical_name: str) -> Optional["Modifier"]:
917        """
918            Return a modifier from a canonical name (contract.signature())
919        Args:
920            canonical_name (str): canonical name of the modifier
921        Returns:
922            Modifier
923        """
924        return next((m for m in self.modifiers if m.canonical_name == canonical_name), None)

Return a modifier from a canonical name (contract.signature()) Args: canonical_name (str): canonical name of the modifier Returns: Modifier

def get_state_variable_from_name( self, variable_name: str) -> Union[slither.core.variables.state_variable.StateVariable, NoneType]:
926    def get_state_variable_from_name(self, variable_name: str) -> Optional["StateVariable"]:
927        """
928        Return a state variable from a name
929
930        :param variable_name:
931        """
932        return next((v for v in self.state_variables if v.name == variable_name), None)

Return a state variable from a name

Parameters
  • variable_name:
def get_state_variable_from_canonical_name( self, canonical_name: str) -> Union[slither.core.variables.state_variable.StateVariable, NoneType]:
934    def get_state_variable_from_canonical_name(
935        self, canonical_name: str
936    ) -> Optional["StateVariable"]:
937        """
938            Return a state variable from a canonical_name
939        Args:
940            canonical_name (str): name of the variable
941        Returns:
942            StateVariable
943        """
944        return next((v for v in self.state_variables if v.canonical_name == canonical_name), None)

Return a state variable from a canonical_name Args: canonical_name (str): name of the variable Returns: StateVariable

def get_structure_from_name( self, structure_name: str) -> Union[slither.core.declarations.structure_contract.StructureContract, NoneType]:
946    def get_structure_from_name(self, structure_name: str) -> Optional["StructureContract"]:
947        """
948            Return a structure from a name
949        Args:
950            structure_name (str): name of the structure
951        Returns:
952            StructureContract
953        """
954        return next((st for st in self.structures if st.name == structure_name), None)

Return a structure from a name Args: structure_name (str): name of the structure Returns: StructureContract

def get_structure_from_canonical_name( self, structure_name: str) -> Union[slither.core.declarations.structure_contract.StructureContract, NoneType]:
956    def get_structure_from_canonical_name(
957        self, structure_name: str
958    ) -> Optional["StructureContract"]:
959        """
960            Return a structure from a canonical name
961        Args:
962            structure_name (str): canonical name of the structure
963        Returns:
964            StructureContract
965        """
966        return next((st for st in self.structures if st.canonical_name == structure_name), None)

Return a structure from a canonical name Args: structure_name (str): canonical name of the structure Returns: StructureContract

def get_event_from_signature(self, event_signature: str) -> Union[ForwardRef('Event'), NoneType]:
968    def get_event_from_signature(self, event_signature: str) -> Optional["Event"]:
969        """
970            Return an event from a signature
971        Args:
972            event_signature (str): signature of the event
973        Returns:
974            Event
975        """
976        return next((e for e in self.events if e.full_name == event_signature), None)

Return an event from a signature Args: event_signature (str): signature of the event Returns: Event

def get_event_from_canonical_name(self, event_canonical_name: str) -> Union[ForwardRef('Event'), NoneType]:
978    def get_event_from_canonical_name(self, event_canonical_name: str) -> Optional["Event"]:
979        """
980            Return an event from a canonical name
981        Args:
982            event_canonical_name (str): name of the event
983        Returns:
984            Event
985        """
986        return next((e for e in self.events if e.canonical_name == event_canonical_name), None)

Return an event from a canonical name Args: event_canonical_name (str): name of the event Returns: Event

def get_enum_from_name( self, enum_name: str) -> Union[slither.core.declarations.enum.Enum, NoneType]:
988    def get_enum_from_name(self, enum_name: str) -> Optional["Enum"]:
989        """
990            Return an enum from a name
991        Args:
992            enum_name (str): name of the enum
993        Returns:
994            Enum
995        """
996        return next((e for e in self.enums if e.name == enum_name), None)

Return an enum from a name Args: enum_name (str): name of the enum Returns: Enum

def get_enum_from_canonical_name( self, enum_name: str) -> Union[slither.core.declarations.enum.Enum, NoneType]:
 998    def get_enum_from_canonical_name(self, enum_name: str) -> Optional["Enum"]:
 999        """
1000            Return an enum from a canonical name
1001        Args:
1002            enum_name (str): canonical name of the enum
1003        Returns:
1004            Enum
1005        """
1006        return next((e for e in self.enums if e.canonical_name == enum_name), None)

Return an enum from a canonical name Args: enum_name (str): canonical name of the enum Returns: Enum

def get_functions_overridden_by( self, function: slither.core.declarations.function.Function) -> list[slither.core.declarations.function.Function]:
1008    def get_functions_overridden_by(self, function: "Function") -> List["Function"]:
1009        """
1010            Return the list of functions overridden by the function
1011        Args:
1012            (core.Function)
1013        Returns:
1014            list(core.Function)
1015
1016        """
1017        return function.overrides

Return the list of functions overridden by the function Args: (core.Function) Returns: list(core.Function)

1026    @property
1027    def all_functions_called(self) -> List["InternalCallType"]:
1028        """
1029        list(Function): List of functions reachable from the contract
1030        Includes super, and private/internal functions not shadowed
1031        """
1032        if self._all_functions_called is None:
1033            all_functions = [f for f in self.functions + self.modifiers if not f.is_shadowed]  # type: ignore
1034            all_callss = [f.all_internal_calls() for f in all_functions] + [list(all_functions)]
1035            all_calls = [item for sublist in all_callss for item in sublist]
1036            all_calls = list(set(all_calls))
1037
1038            all_constructors = [c.constructor for c in self.inheritance if c.constructor]
1039            all_constructors = list(set(all_constructors))
1040
1041            set_all_calls = set(all_calls + list(all_constructors))
1042
1043            self._all_functions_called = [c for c in set_all_calls if isinstance(c, Function)]
1044        return self._all_functions_called

list(Function): List of functions reachable from the contract Includes super, and private/internal functions not shadowed

all_state_variables_written: list[slither.core.variables.state_variable.StateVariable]
1046    @property
1047    def all_state_variables_written(self) -> List["StateVariable"]:
1048        """
1049        list(StateVariable): List all of the state variables written
1050        """
1051        all_state_variables_writtens = [
1052            f.all_state_variables_written() for f in self.functions + self.modifiers  # type: ignore
1053        ]
1054        all_state_variables_written = [
1055            item for sublist in all_state_variables_writtens for item in sublist
1056        ]
1057        return list(set(all_state_variables_written))

list(StateVariable): List all of the state variables written

all_state_variables_read: list[slither.core.variables.state_variable.StateVariable]
1059    @property
1060    def all_state_variables_read(self) -> List["StateVariable"]:
1061        """
1062        list(StateVariable): List all of the state variables read
1063        """
1064        all_state_variables_reads = [
1065            f.all_state_variables_read() for f in self.functions + self.modifiers  # type: ignore
1066        ]
1067        all_state_variables_read = [
1068            item for sublist in all_state_variables_reads for item in sublist
1069        ]
1070        return list(set(all_state_variables_read))

list(StateVariable): List all of the state variables read

all_library_calls: list[tuple[Contract, slither.core.declarations.function.Function]]
1072    @property
1073    def all_library_calls(self) -> List["LibraryCallType"]:
1074        """
1075        list((Contract, Function): List all of the libraries func called
1076        """
1077        all_high_level_callss = [f.all_library_calls() for f in self.functions + self.modifiers]  # type: ignore
1078        all_high_level_calls = [item for sublist in all_high_level_callss for item in sublist]
1079        return list(set(all_high_level_calls))

list((Contract, Function): List all of the libraries func called

all_high_level_calls: list[tuple[Contract, typing.Union[slither.core.declarations.function.Function, slither.core.variables.variable.Variable]]]
1081    @property
1082    def all_high_level_calls(self) -> List["HighLevelCallType"]:
1083        """
1084        list((Contract, Function|Variable)): List all of the external high level calls
1085        """
1086        all_high_level_callss = [f.all_high_level_calls() for f in self.functions + self.modifiers]  # type: ignore
1087        all_high_level_calls = [item for sublist in all_high_level_callss for item in sublist]
1088        return list(set(all_high_level_calls))

list((Contract, Function|Variable)): List all of the external high level calls

def get_summary( self, include_shadowed: bool = True) -> Tuple[str, List[str], List[str], List, List]:
1097    def get_summary(
1098        self, include_shadowed: bool = True
1099    ) -> Tuple[str, List[str], List[str], List, List]:
1100        """Return the function summary
1101
1102        :param include_shadowed: boolean to indicate if shadowed functions should be included (default True)
1103        Returns:
1104            (str, list, list, list, list): (name, inheritance, variables, fuction summaries, modifier summaries)
1105        """
1106        func_summaries = [
1107            f.get_summary() for f in self.functions if (not f.is_shadowed or include_shadowed)
1108        ]
1109        modif_summaries = [
1110            f.get_summary() for f in self.modifiers if (not f.is_shadowed or include_shadowed)
1111        ]
1112        return (
1113            self.name,
1114            [str(x) for x in self.inheritance],
1115            [str(x) for x in self.variables],
1116            func_summaries,
1117            modif_summaries,
1118        )

Return the function summary

Parameters
  • include_shadowed: boolean to indicate if shadowed functions should be included (default True) Returns: (str, list, list, list, list): (name, inheritance, variables, fuction summaries, modifier summaries)
def is_signature_only(self) -> bool:
1120    def is_signature_only(self) -> bool:
1121        """Detect if the contract has only abstract functions
1122
1123        Returns:
1124            bool: true if the function are abstract functions
1125        """
1126        return all((not f.is_implemented) for f in self.functions)

Detect if the contract has only abstract functions

Returns: bool: true if the function are abstract functions

def ercs(self) -> List[str]:
1135    def ercs(self) -> List[str]:
1136        """
1137        Return the ERC implemented
1138        :return: list of string
1139        """
1140        all_erc = [
1141            ("ERC20", self.is_erc20),
1142            ("ERC165", self.is_erc165),
1143            ("ERC1820", self.is_erc1820),
1144            ("ERC223", self.is_erc223),
1145            ("ERC721", self.is_erc721),
1146            ("ERC777", self.is_erc777),
1147            ("ERC2612", self.is_erc2612),
1148            ("ERC1363", self.is_erc1363),
1149            ("ERC4626", self.is_erc4626),
1150        ]
1151
1152        return [erc for erc, is_erc in all_erc if is_erc()]

Return the ERC implemented

Returns

list of string

def is_erc20(self) -> bool:
1154    def is_erc20(self) -> bool:
1155        """
1156            Check if the contract is an erc20 token
1157
1158            Note: it does not check for correct return values
1159        :return: Returns a true if the contract is an erc20
1160        """
1161        full_names = self.functions_signatures
1162        return all(s in full_names for s in ERC20_signatures)

Check if the contract is an erc20 token

Note: it does not check for correct return values
Returns

Returns a true if the contract is an erc20

def is_erc165(self) -> bool:
1164    def is_erc165(self) -> bool:
1165        """
1166            Check if the contract is an erc165 token
1167
1168            Note: it does not check for correct return values
1169        :return: Returns a true if the contract is an erc165
1170        """
1171        full_names = self.functions_signatures
1172        return all(s in full_names for s in ERC165_signatures)

Check if the contract is an erc165 token

Note: it does not check for correct return values
Returns

Returns a true if the contract is an erc165

def is_erc1820(self) -> bool:
1174    def is_erc1820(self) -> bool:
1175        """
1176            Check if the contract is an erc1820
1177
1178            Note: it does not check for correct return values
1179        :return: Returns a true if the contract is an erc165
1180        """
1181        full_names = self.functions_signatures
1182        return all(s in full_names for s in ERC1820_signatures)

Check if the contract is an erc1820

Note: it does not check for correct return values
Returns

Returns a true if the contract is an erc165

def is_erc223(self) -> bool:
1184    def is_erc223(self) -> bool:
1185        """
1186            Check if the contract is an erc223 token
1187
1188            Note: it does not check for correct return values
1189        :return: Returns a true if the contract is an erc223
1190        """
1191        full_names = self.functions_signatures
1192        return all(s in full_names for s in ERC223_signatures)

Check if the contract is an erc223 token

Note: it does not check for correct return values
Returns

Returns a true if the contract is an erc223

def is_erc721(self) -> bool:
1194    def is_erc721(self) -> bool:
1195        """
1196            Check if the contract is an erc721 token
1197
1198            Note: it does not check for correct return values
1199        :return: Returns a true if the contract is an erc721
1200        """
1201        full_names = self.functions_signatures
1202        return all(s in full_names for s in ERC721_signatures)

Check if the contract is an erc721 token

Note: it does not check for correct return values
Returns

Returns a true if the contract is an erc721

def is_erc777(self) -> bool:
1204    def is_erc777(self) -> bool:
1205        """
1206            Check if the contract is an erc777
1207
1208            Note: it does not check for correct return values
1209        :return: Returns a true if the contract is an erc165
1210        """
1211        full_names = self.functions_signatures
1212        return all(s in full_names for s in ERC777_signatures)

Check if the contract is an erc777

Note: it does not check for correct return values
Returns

Returns a true if the contract is an erc165

def is_erc1155(self) -> bool:
1214    def is_erc1155(self) -> bool:
1215        """
1216            Check if the contract is an erc1155
1217
1218            Note: it does not check for correct return values
1219        :return: Returns a true if the contract is an erc1155
1220        """
1221        full_names = self.functions_signatures
1222        return all(s in full_names for s in ERC1155_signatures)

Check if the contract is an erc1155

Note: it does not check for correct return values
Returns

Returns a true if the contract is an erc1155

def is_erc4626(self) -> bool:
1224    def is_erc4626(self) -> bool:
1225        """
1226            Check if the contract is an erc4626
1227
1228            Note: it does not check for correct return values
1229        :return: Returns a true if the contract is an erc4626
1230        """
1231        full_names = self.functions_signatures
1232        return all(s in full_names for s in ERC4626_signatures)

Check if the contract is an erc4626

Note: it does not check for correct return values
Returns

Returns a true if the contract is an erc4626

def is_erc2612(self) -> bool:
1234    def is_erc2612(self) -> bool:
1235        """
1236            Check if the contract is an erc2612
1237
1238            Note: it does not check for correct return values
1239        :return: Returns a true if the contract is an erc2612
1240        """
1241        full_names = self.functions_signatures
1242        return all(s in full_names for s in ERC2612_signatures)

Check if the contract is an erc2612

Note: it does not check for correct return values
Returns

Returns a true if the contract is an erc2612

def is_erc1363(self) -> bool:
1244    def is_erc1363(self) -> bool:
1245        """
1246            Check if the contract is an erc1363
1247
1248            Note: it does not check for correct return values
1249        :return: Returns a true if the contract is an erc1363
1250        """
1251        full_names = self.functions_signatures
1252        return all(s in full_names for s in ERC1363_signatures)

Check if the contract is an erc1363

Note: it does not check for correct return values
Returns

Returns a true if the contract is an erc1363

def is_erc4524(self) -> bool:
1254    def is_erc4524(self) -> bool:
1255        """
1256            Check if the contract is an erc4524
1257
1258            Note: it does not check for correct return values
1259        :return: Returns a true if the contract is an erc4524
1260        """
1261        full_names = self.functions_signatures
1262        return all(s in full_names for s in ERC4524_signatures)

Check if the contract is an erc4524

Note: it does not check for correct return values
Returns

Returns a true if the contract is an erc4524

is_token: bool
1264    @property
1265    def is_token(self) -> bool:
1266        """
1267        Check if the contract follows one of the standard ERC token
1268        :return:
1269        """
1270        return (
1271            self.is_erc20()
1272            or self.is_erc721()
1273            or self.is_erc165()
1274            or self.is_erc223()
1275            or self.is_erc777()
1276            or self.is_erc1155()
1277        )

Check if the contract follows one of the standard ERC token

Returns
def is_possible_erc20(self) -> bool:
1279    def is_possible_erc20(self) -> bool:
1280        """
1281        Checks if the provided contract could be attempting to implement ERC20 standards.
1282
1283        :return: Returns a boolean indicating if the provided contract met the token standard.
1284        """
1285        # We do not check for all the functions, as name(), symbol(), might give too many FPs
1286        full_names = self.functions_signatures
1287        return (
1288            "transfer(address,uint256)" in full_names
1289            or "transferFrom(address,address,uint256)" in full_names
1290            or "approve(address,uint256)" in full_names
1291        )

Checks if the provided contract could be attempting to implement ERC20 standards.

Returns

Returns a boolean indicating if the provided contract met the token standard.

def is_possible_erc721(self) -> bool:
1293    def is_possible_erc721(self) -> bool:
1294        """
1295        Checks if the provided contract could be attempting to implement ERC721 standards.
1296
1297        :return: Returns a boolean indicating if the provided contract met the token standard.
1298        """
1299        # We do not check for all the functions, as name(), symbol(), might give too many FPs
1300        full_names = self.functions_signatures
1301        return (
1302            "ownerOf(uint256)" in full_names
1303            or "safeTransferFrom(address,address,uint256,bytes)" in full_names
1304            or "safeTransferFrom(address,address,uint256)" in full_names
1305            or "setApprovalForAll(address,bool)" in full_names
1306            or "getApproved(uint256)" in full_names
1307            or "isApprovedForAll(address,address)" in full_names
1308        )

Checks if the provided contract could be attempting to implement ERC721 standards.

Returns

Returns a boolean indicating if the provided contract met the token standard.

is_possible_token: bool
1310    @property
1311    def is_possible_token(self) -> bool:
1312        """
1313        Check if the contract is a potential token (it might not implement all the functions)
1314        :return:
1315        """
1316        return self.is_possible_erc20() or self.is_possible_erc721()

Check if the contract is a potential token (it might not implement all the functions)

Returns
def is_from_dependency(self) -> bool:
1325    def is_from_dependency(self) -> bool:
1326        return self.compilation_unit.core.crytic_compile.is_dependency(
1327            self.source_mapping.filename.absolute
1328        )
is_truffle_migration: bool
1337    @property
1338    def is_truffle_migration(self) -> bool:
1339        """
1340        Return true if the contract is the Migrations contract needed for Truffle
1341        :return:
1342        """
1343        if self.compilation_unit.core.crytic_compile.platform == PlatformType.TRUFFLE:
1344            if self.name == "Migrations":
1345                paths = Path(self.source_mapping.filename.absolute).parts
1346                if len(paths) >= 2:
1347                    return paths[-2] == "contracts" and paths[-1] == "migrations.sol"
1348        return False

Return true if the contract is the Migrations contract needed for Truffle

Returns
is_test: bool
1350    @property
1351    def is_test(self) -> bool:
1352        return is_test_contract(self) or self.is_truffle_migration  # type: ignore
def update_read_write_using_ssa(self) -> None:
1361    def update_read_write_using_ssa(self) -> None:
1362        for function in self.functions + list(self.modifiers):
1363            function.update_read_write_using_ssa()
is_upgradeable: bool
1372    @property
1373    def is_upgradeable(self) -> bool:
1374        if self._is_upgradeable is None:
1375            self._is_upgradeable = False
1376            initializable = self.file_scope.get_contract_from_name("Initializable")
1377            if initializable:
1378                if initializable in self.inheritance:
1379                    self._is_upgradeable = True
1380            else:
1381                for contract in self.inheritance + [self]:
1382                    # This might lead to false positive
1383                    # Not sure why pylint is having a trouble here
1384                    # pylint: disable=no-member
1385                    lower_name = contract.name.lower()
1386                    if "upgradeable" in lower_name or "upgradable" in lower_name:
1387                        self._is_upgradeable = True
1388                        break
1389                    if "initializable" in lower_name:
1390                        self._is_upgradeable = True
1391                        break
1392        return self._is_upgradeable
is_upgradeable_proxy: bool
1398    @property
1399    def is_upgradeable_proxy(self) -> bool:
1400        from slither.core.cfg.node import NodeType
1401        from slither.slithir.operations import LowLevelCall
1402
1403        if self._is_upgradeable_proxy is None:
1404            self._is_upgradeable_proxy = False
1405            if "Proxy" in self.name:
1406                self._is_upgradeable_proxy = True
1407                return True
1408            for f in self.functions:
1409                if f.is_fallback:
1410                    for node in f.all_nodes():
1411                        for ir in node.irs:
1412                            if isinstance(ir, LowLevelCall) and ir.function_name == "delegatecall":
1413                                self._is_upgradeable_proxy = True
1414                                return self._is_upgradeable_proxy
1415                        if node.type == NodeType.ASSEMBLY:
1416                            inline_asm = node.inline_asm
1417                            if inline_asm:
1418                                if "delegatecall" in inline_asm:
1419                                    self._is_upgradeable_proxy = True
1420                                    return self._is_upgradeable_proxy
1421        return self._is_upgradeable_proxy
upgradeable_version: Union[str, NoneType]
1427    @property
1428    def upgradeable_version(self) -> Optional[str]:
1429        return self._upgradeable_version
is_incorrectly_constructed: bool
1442    @property
1443    def is_incorrectly_constructed(self) -> bool:
1444        """
1445        Return true if there was an internal Slither's issue when analyzing the contract
1446        :return:
1447        """
1448        return self._is_incorrectly_parsed

Return true if there was an internal Slither's issue when analyzing the contract

Returns
def add_constructor_variables(self) -> None:
1454    def add_constructor_variables(self) -> None:
1455        from slither.core.declarations.function_contract import FunctionContract
1456
1457        if self.state_variables:
1458            for (idx, variable_candidate) in enumerate(self.state_variables):
1459                if variable_candidate.expression and not variable_candidate.is_constant:
1460
1461                    constructor_variable = FunctionContract(self.compilation_unit)
1462                    constructor_variable.set_function_type(FunctionType.CONSTRUCTOR_VARIABLES)
1463                    constructor_variable.set_contract(self)  # type: ignore
1464                    constructor_variable.set_contract_declarer(self)  # type: ignore
1465                    constructor_variable.set_visibility("internal")
1466                    # For now, source mapping of the constructor variable is the whole contract
1467                    # Could be improved with a targeted source mapping
1468                    constructor_variable.set_offset(self.source_mapping, self.compilation_unit)
1469                    self._functions[constructor_variable.canonical_name] = constructor_variable
1470
1471                    prev_node = self._create_node(
1472                        constructor_variable, 0, variable_candidate, constructor_variable
1473                    )
1474                    variable_candidate.node_initialization = prev_node
1475                    counter = 1
1476                    for v in self.state_variables[idx + 1 :]:
1477                        if v.expression and not v.is_constant:
1478                            next_node = self._create_node(
1479                                constructor_variable, counter, v, prev_node.scope
1480                            )
1481                            v.node_initialization = next_node
1482                            prev_node.add_son(next_node)
1483                            next_node.add_father(prev_node)
1484                            prev_node = next_node
1485                            counter += 1
1486                    break
1487
1488            for (idx, variable_candidate) in enumerate(self.state_variables):
1489                if variable_candidate.expression and variable_candidate.is_constant:
1490
1491                    constructor_variable = FunctionContract(self.compilation_unit)
1492                    constructor_variable.set_function_type(
1493                        FunctionType.CONSTRUCTOR_CONSTANT_VARIABLES
1494                    )
1495                    constructor_variable.set_contract(self)  # type: ignore
1496                    constructor_variable.set_contract_declarer(self)  # type: ignore
1497                    constructor_variable.set_visibility("internal")
1498                    # For now, source mapping of the constructor variable is the whole contract
1499                    # Could be improved with a targeted source mapping
1500                    constructor_variable.set_offset(self.source_mapping, self.compilation_unit)
1501                    self._functions[constructor_variable.canonical_name] = constructor_variable
1502
1503                    prev_node = self._create_node(
1504                        constructor_variable, 0, variable_candidate, constructor_variable
1505                    )
1506                    variable_candidate.node_initialization = prev_node
1507                    counter = 1
1508                    for v in self.state_variables[idx + 1 :]:
1509                        if v.expression and v.is_constant:
1510                            next_node = self._create_node(
1511                                constructor_variable, counter, v, prev_node.scope
1512                            )
1513                            v.node_initialization = next_node
1514                            prev_node.add_son(next_node)
1515                            next_node.add_father(prev_node)
1516                            prev_node = next_node
1517                            counter += 1
1518
1519                    break
def convert_expression_to_slithir_ssa(self) -> None:
1555    def convert_expression_to_slithir_ssa(self) -> None:
1556        """
1557        Assume generate_slithir_and_analyze was called on all functions
1558
1559        :return:
1560        """
1561        from slither.slithir.variables import StateIRVariable
1562
1563        all_ssa_state_variables_instances = {}
1564
1565        for contract in self.inheritance:
1566            for v in contract.state_variables_declared:
1567                new_var = StateIRVariable(v)
1568                all_ssa_state_variables_instances[v.canonical_name] = new_var
1569                self._initial_state_variables.append(new_var)
1570
1571        for v in self.variables:
1572            if v.contract == self:
1573                new_var = StateIRVariable(v)
1574                all_ssa_state_variables_instances[v.canonical_name] = new_var
1575                self._initial_state_variables.append(new_var)
1576
1577        for func in self.functions + list(self.modifiers):
1578            func.generate_slithir_ssa(all_ssa_state_variables_instances)

Assume generate_slithir_and_analyze was called on all functions

Returns
def fix_phi(self) -> None:
1580    def fix_phi(self) -> None:
1581        last_state_variables_instances: Dict[str, List["StateVariable"]] = {}
1582        initial_state_variables_instances: Dict[str, "StateVariable"] = {}
1583        for v in self._initial_state_variables:
1584            last_state_variables_instances[v.canonical_name] = []
1585            initial_state_variables_instances[v.canonical_name] = v
1586
1587        for func in self.functions + list(self.modifiers):
1588            result = func.get_last_ssa_state_variables_instances()
1589            for variable_name, instances in result.items():
1590                # TODO: investigate the next operation
1591                last_state_variables_instances[variable_name] += list(instances)
1592
1593        for func in self.functions + list(self.modifiers):
1594            func.fix_phi(last_state_variables_instances, initial_state_variables_instances)