tronpytool.contract API documentation

# Module `tronpytool.contract`

Expand source code

    #!/usr/bin/env python
    # --------------------------------------------------------------------
    # Copyright (c) iEXBase. All rights reserved.
    # Licensed under the MIT License.
    # See License.txt in the project root for license information.
    # --------------------------------------------------------------------

    import copy
    from typing import Tuple, Union

    from eth_abi import decode_abi
    from eth_utils import (
        function_abi_to_4byte_selector,
        to_hex
    )
    from hexbytes import HexBytes
    from trx_utils import (
        encode_hex,
        is_text,
        deprecated_for,
        combomethod
    )
    from trx_utils.typing import HexStr

    from tronpytool.common.abi import (
        filter_by_type,
        merge_args_and_kwargs,
        abi_to_signature,
        fallback_func_abi_exists,
        check_if_arguments_can_be_encoded,
        map_abi_data, filter_by_name
    )
    from tronpytool.common.contracts import (
        find_matching_fn_abi,
        encode_abi,
        get_function_info,
        FallbackFn
    )
    from tronpytool.common.datatypes import PropertyCheckingFactory
    from tronpytool.common.encoding import to_4byte_hex
    from tronpytool.common.normalizers import (
        normalize_abi,
        normalize_bytecode,
        BASE_RETURN_NORMALIZERS
    )
    from tronpytool.exceptions import (
        NoABIFunctionsFound,
        MismatchedABI,
        FallbackNotFound
    )

    class NonExistentFallbackFunction:
        @staticmethod
        def _raise_exception():
            raise FallbackNotFound("No fallback function was found in the contract ABI.")

        def __getattr__(self, attr):
            return NonExistentFallbackFunction._raise_exception

    class ContractFunction:
        """Base class for contract functions"""
        address = None
        function_identifier = None
        tron = None
        contract_abi = None
        abi = None
        transaction = None
        arguments = None

        def __init__(self, abi=None):
            self.abi = abi
            self.fn_name = type(self).__name__

        def __call__(self, *args, **kwargs):
            clone = copy.copy(self)
            if args is None:
                clone.args = tuple()
            else:
                clone.args = args

            if kwargs is None:
                clone.kwargs = {}
            else:
                clone.kwargs = kwargs
            clone._set_function_info()
            return clone

        def _set_function_info(self):
            if not self.abi:
                self.abi = find_matching_fn_abi(
                    self.contract_abi,
                    self.function_identifier,
                    self.args,
                    self.kwargs
                )
            if self.function_identifier is FallbackFn:
                self.selector = encode_hex(b'')
            elif is_text(self.function_identifier):
                self.selector = encode_hex(function_abi_to_4byte_selector(self.abi))
            else:
                raise TypeError("Unsupported function identifier")

            self.arguments = merge_args_and_kwargs(self.abi, self.args, self.kwargs)

        @classmethod
        def factory(cls, class_name, **kwargs):
            return PropertyCheckingFactory(class_name, (cls,), kwargs)(kwargs.get('abi'))

        def __repr__(self):
            if self.abi:
                _repr = '<Function %s' % abi_to_signature(self.abi)
                if self.arguments is not None:
                    _repr += ' bound to %r' % (self.arguments,)
                return _repr + '>'
            return '<Function %s>' % self.fn_name

    class ContractFunctions:
        """
        Class containing contract function objects
        """

        def __init__(self, _abi, tron, address=None):
            if _abi:
                self._functions = filter_by_type('function', _abi)
                for func in self._functions:
                    setattr(self, func['name'],
                            ContractFunction.factory(
                                func['name'],
                                tron=tron,
                                contract_abi=_abi,
                                address=address,
                                function_identifier=func['name']))
                self.abi = _abi

        def get_abi_by_name(self, func_name: str) -> dict:
            """Find the correct function abi for the name"""
            t = filter_by_name(func_name, self.abi)
            if len(t) > 0:
                return t[0]
            raise NoABIFunctionsFound(
                "The abi for this contract contains no function definitions. ",
                "Are you sure you provided the correct call name from the abi?"
            )

        def print_functions(self):
            """only for testing, list all the functions that can be called. """
            for func in self._functions:
                if func['type'] == 'function':
                    if func['stateMutability'] in ['pure', 'view']:
                        printdebugfunc('read', func)
                    if func['stateMutability'] in ['nonpayable']:
                        printdebugfunc('write', func)

                if func['type'] == 'constructor':
                    printdebugfunc('constructor', func)
                print("=====")
                print(func)

        def __iter__(self):
            if not hasattr(self, '_functions') or not self._functions:
                return

            for func in self._functions:
                yield func['name']

        def __getattr__(self, function_name):
            if '_functions' not in self.__dict__:
                raise NoABIFunctionsFound(
                    "The abi for this contract contains no function definitions. ",
                    "Are you sure you provided the correct contract abi?"
                )
            elif function_name not in self.__dict__['_functions']:
                raise MismatchedABI(
                    "The function '{}' was not found in this contract's abi. ".format(function_name),
                    "Are you sure you provided the correct contract abi?"
                )
            else:
                return super().__getattribute__(function_name)

        def __getitem__(self, function_name):
            return getattr(self, function_name)

    class Contract:
        # set during class construction
        tron = None

        # instance level properties
        address = None

        # class properties (overridable at instance level)
        abi = None

        bytecode = None
        bytecode_runtime = None

        functions = None
        events = None
        fallback = None

        def __init__(self, address=None):
            """Create a new smart contract proxy object.
            :param address: Contract address as 0x hex string
            """
            if self.tron is None:
                raise AttributeError(
                    'The `Contract` class has not been initialized.  Please use the '
                    '`tron.contract` interface to create your contract class.'
                )

            if address:
                self.address = self.tron.address.to_hex(address)

            if not self.address:
                raise TypeError("The address argument is required to instantiate a contract.")

            self.functions = ContractFunctions(self.abi, self.tron, self.address)
            self.fallback = Contract.get_fallback_function(self.abi, self.tron, self.address)

        @classmethod
        def factory(cls, tron: any, class_name=None, **kwargs) -> "PropertyCheckingFactory":

            kwargs['tron'] = tron
            normalizers = {
                'abi': normalize_abi,
                'bytecode': normalize_bytecode,
                'bytecode_runtime': normalize_bytecode,
            }

            contract = PropertyCheckingFactory(
                class_name or cls.__name__,
                (cls,),
                kwargs,
                normalizers=normalizers
            )

            setattr(contract, 'functions', ContractFunctions(contract.abi, contract.tron))
            setattr(contract, 'fallback', Contract.get_fallback_function(contract.abi, contract.tron))

            return contract

        @classmethod
        @deprecated_for("contract.constructor.transact")
        def deploy(cls, **kwargs):
            """Deploy Contract

            This method can also be done in "contract.constructor.transact"

            Deploys a contract.
            Returns TransactionExtention, which contains an unsigned transaction.

            Example:
            .. code-block:: python
                >>> MyContract.deploy(
                    fee_limit=10**9,
                    call_value=0,
                    consume_user_resource_percent=10
                )

            Args:
                **kwargs: Transaction parameters for the deployment
                transaction as a dict

            """

            return cls.tron.transaction_builder.create_smart_contract(
                **kwargs,
                abi=cls.abi,
                bytecode=to_hex(cls.bytecode)
            )

        @classmethod
        def constructor(cls) -> any:
            if cls.bytecode is None:
                raise ValueError(
                    "Cannot call constructor on a contract that does not have 'bytecode' associated "
                    "with it"
                )
            return ContractConstructor(cls.tron,
                                       cls.abi,
                                       cls.bytecode)

        @combomethod
        def encodeABI(cls, fn_name, args=None, kwargs=None, data=None) -> Union[HexStr, str]:
            """Encodes the arguments using the Tron ABI for the contract function
            that matches the given name and arguments..
            """
            fn_abi, fn_selector, fn_arguments = get_function_info(
                fn_name, contract_abi=cls.abi, args=args, kwargs=kwargs,
            )

            if data is None:
                data = fn_selector

            return encode_abi(cls.tron, fn_abi, fn_arguments, data)

        @staticmethod
        def get_fallback_function(abi, tron, address=None) -> any:
            if abi and fallback_func_abi_exists(abi):
                return ContractFunction.factory(
                    'fallback',
                    tron=tron,
                    contract_abi=abi,
                    address=address,
                    function_identifier=FallbackFn)()

            return NonExistentFallbackFunction()

        @combomethod
        def all_functions(self) -> list:
            return find_functions_by_identifier(
                self.abi, self.tron, self.address, lambda _: True
            )

        @combomethod
        def get_function_by_signature(self, signature) -> list:
            if ' ' in signature:
                raise ValueError(
                    'Function signature should not contain any spaces. '
                    'Found spaces in input: %s' % signature
                )

            def callable_check(fn_abi):
                return abi_to_signature(fn_abi) == signature

            fns = find_functions_by_identifier(self.abi, self.tron, self.address, callable_check)
            return get_function_by_identifier(fns, 'signature')

        @combomethod
        def find_functions_by_name(self, fn_name) -> list:
            def callable_check(fn_abi):
                return fn_abi['name'] == fn_name

            return find_functions_by_identifier(
                self.abi, self.tron, self.address, callable_check
            )

        @combomethod
        def get_function_by_name(self, fn_name) -> any:
            fns = self.find_functions_by_name(fn_name)
            return get_function_by_identifier(fns, 'name')

        @combomethod
        def get_function_by_selector(self, selector):
            def callable_check(fn_abi) -> bool:
                return encode_hex(function_abi_to_4byte_selector(fn_abi)) == to_4byte_hex(selector)

            fns = find_functions_by_identifier(self.abi, self.tron, self.address, callable_check)
            return get_function_by_identifier(fns, 'selector')

        @combomethod
        def decode_function_input(self, data) -> Tuple[any, dict]:
            data = HexBytes(data)
            selector, params = data[:4], data[4:]
            func = self.get_function_by_selector(selector)
            names = [x['name'] for x in func.abi['inputs']]
            types = [x['type'] for x in func.abi['inputs']]
            decoded = decode_abi(types, params)
            normalized = map_abi_data(BASE_RETURN_NORMALIZERS, types, decoded)
            return func, dict(zip(names, normalized))

        @combomethod
        def find_functions_by_args(self, *args) -> list:
            def callable_check(fn_abi) -> bool:
                return check_if_arguments_can_be_encoded(fn_abi, args=args, kwargs={})

            return find_functions_by_identifier(
                self.abi, self.tron, self.address, callable_check
            )

        @combomethod
        def get_function_by_args(self, *args):
            fns = self.find_functions_by_args(*args)
            return get_function_by_identifier(fns, 'args')

    class ContractConstructor:
        """
        Class for contract constructor API.
        """

        def __init__(self, tron, abi, bytecode):
            self.tron = tron
            self.abi = abi
            self.bytecode = bytecode

        @staticmethod
        def check_forbidden_keys_in_transaction(transaction, forbidden_keys=None):
            keys_found = set(transaction.keys()) & set(forbidden_keys)
            if keys_found:
                raise ValueError("Cannot set {} in transaction".format(', '.join(keys_found)))

        @combomethod
        def transact(self, **kwargs):
            """Deploy Contract

            Deploys a contract.
            Returns TransactionExtention, which contains an unsigned transaction.

            Args:
                **kwargs: Additional options to send
            """

            return self.tron.transaction_builder.create_smart_contract(
                **kwargs,
                abi=self.abi,
                bytecode=to_hex(self.bytecode)
            )

    def find_functions_by_identifier(contract_abi, tron, address, callable_check) -> list:
        fns_abi = filter_by_type('function', contract_abi)
        return [
            ContractFunction.factory(
                fn_abi['name'],
                tron=tron,
                contract_abi=contract_abi,
                address=address,
                function_identifier=fn_abi['name'],
                abi=fn_abi
            )
            for fn_abi in fns_abi
            if callable_check(fn_abi)
        ]

    def get_function_by_identifier(fns, identifier):
        if len(fns) > 1:
            raise ValueError(
                'Found multiple functions with matching {0}. '
                'Found: {1!r}'.format(identifier, fns)
            )
        elif len(fns) == 0:
            raise ValueError(
                'Could not find any function with matching {0}'.format(identifier)
            )
        return fns[0]

    def printdebugfunc(typecontrol, func):
        b = "{} {}({}) {}"
        input_space = ""
        oput_space = ""

        try:
            input_space = func['input']
        except KeyError:
            pass

        try:
            oput_space = "-> {}".format(func['output'])
        except KeyError:
            pass

        print(b.format(typecontrol, func['name'], input_space, oput_space))
        print("=====")

## Functions

`def find_functions_by_identifier(contract_abi, tron, address, callable_check) ‑> list`
  Expand source code

      def find_functions_by_identifier(contract_abi, tron, address, callable_check) -> list:
          fns_abi = filter_by_type('function', contract_abi)
          return [
              ContractFunction.factory(
                  fn_abi['name'],
                  tron=tron,
                  contract_abi=contract_abi,
                  address=address,
                  function_identifier=fn_abi['name'],
                  abi=fn_abi
              )
              for fn_abi in fns_abi
              if callable_check(fn_abi)
          ]

`def get_function_by_identifier(fns, identifier)`
  Expand source code

      def get_function_by_identifier(fns, identifier):
          if len(fns) > 1:
              raise ValueError(
                  'Found multiple functions with matching {0}. '
                  'Found: {1!r}'.format(identifier, fns)
              )
          elif len(fns) == 0:
              raise ValueError(
                  'Could not find any function with matching {0}'.format(identifier)
              )
          return fns[0]

`def printdebugfunc(typecontrol, func)`
  Expand source code

      def printdebugfunc(typecontrol, func):
          b = "{} {}({}) {}"
          input_space = ""
          oput_space = ""

          try:
              input_space = func['input']
          except KeyError:
              pass

          try:
              oput_space = "-> {}".format(func['output'])
          except KeyError:
              pass

          print(b.format(typecontrol, func['name'], input_space, oput_space))
          print("=====")

## Classes

`class Contract (address=None)`

  Create a new smart contract proxy object. :param address: Contract address as 0x hex string

  Expand source code

      class Contract:
          # set during class construction
          tron = None

          # instance level properties
          address = None

          # class properties (overridable at instance level)
          abi = None

          bytecode = None
          bytecode_runtime = None

          functions = None
          events = None
          fallback = None

          def __init__(self, address=None):
              """Create a new smart contract proxy object.
              :param address: Contract address as 0x hex string
              """
              if self.tron is None:
                  raise AttributeError(
                      'The `Contract` class has not been initialized.  Please use the '
                      '`tron.contract` interface to create your contract class.'
                  )

              if address:
                  self.address = self.tron.address.to_hex(address)

              if not self.address:
                  raise TypeError("The address argument is required to instantiate a contract.")

              self.functions = ContractFunctions(self.abi, self.tron, self.address)
              self.fallback = Contract.get_fallback_function(self.abi, self.tron, self.address)

          @classmethod
          def factory(cls, tron: any, class_name=None, **kwargs) -> "PropertyCheckingFactory":

              kwargs['tron'] = tron
              normalizers = {
                  'abi': normalize_abi,
                  'bytecode': normalize_bytecode,
                  'bytecode_runtime': normalize_bytecode,
              }

              contract = PropertyCheckingFactory(
                  class_name or cls.__name__,
                  (cls,),
                  kwargs,
                  normalizers=normalizers
              )

              setattr(contract, 'functions', ContractFunctions(contract.abi, contract.tron))
              setattr(contract, 'fallback', Contract.get_fallback_function(contract.abi, contract.tron))

              return contract

          @classmethod
          @deprecated_for("contract.constructor.transact")
          def deploy(cls, **kwargs):
              """Deploy Contract

              This method can also be done in "contract.constructor.transact"

              Deploys a contract.
              Returns TransactionExtention, which contains an unsigned transaction.

              Example:
              .. code-block:: python
                  >>> MyContract.deploy(
                      fee_limit=10**9,
                      call_value=0,
                      consume_user_resource_percent=10
                  )

              Args:
                  **kwargs: Transaction parameters for the deployment
                  transaction as a dict

              """

              return cls.tron.transaction_builder.create_smart_contract(
                  **kwargs,
                  abi=cls.abi,
                  bytecode=to_hex(cls.bytecode)
              )

          @classmethod
          def constructor(cls) -> any:
              if cls.bytecode is None:
                  raise ValueError(
                      "Cannot call constructor on a contract that does not have 'bytecode' associated "
                      "with it"
                  )
              return ContractConstructor(cls.tron,
                                         cls.abi,
                                         cls.bytecode)

          @combomethod
          def encodeABI(cls, fn_name, args=None, kwargs=None, data=None) -> Union[HexStr, str]:
              """Encodes the arguments using the Tron ABI for the contract function
              that matches the given name and arguments..
              """
              fn_abi, fn_selector, fn_arguments = get_function_info(
                  fn_name, contract_abi=cls.abi, args=args, kwargs=kwargs,
              )

              if data is None:
                  data = fn_selector

              return encode_abi(cls.tron, fn_abi, fn_arguments, data)

          @staticmethod
          def get_fallback_function(abi, tron, address=None) -> any:
              if abi and fallback_func_abi_exists(abi):
                  return ContractFunction.factory(
                      'fallback',
                      tron=tron,
                      contract_abi=abi,
                      address=address,
                      function_identifier=FallbackFn)()

              return NonExistentFallbackFunction()

          @combomethod
          def all_functions(self) -> list:
              return find_functions_by_identifier(
                  self.abi, self.tron, self.address, lambda _: True
              )

          @combomethod
          def get_function_by_signature(self, signature) -> list:
              if ' ' in signature:
                  raise ValueError(
                      'Function signature should not contain any spaces. '
                      'Found spaces in input: %s' % signature
                  )

              def callable_check(fn_abi):
                  return abi_to_signature(fn_abi) == signature

              fns = find_functions_by_identifier(self.abi, self.tron, self.address, callable_check)
              return get_function_by_identifier(fns, 'signature')

          @combomethod
          def find_functions_by_name(self, fn_name) -> list:
              def callable_check(fn_abi):
                  return fn_abi['name'] == fn_name

              return find_functions_by_identifier(
                  self.abi, self.tron, self.address, callable_check
              )

          @combomethod
          def get_function_by_name(self, fn_name) -> any:
              fns = self.find_functions_by_name(fn_name)
              return get_function_by_identifier(fns, 'name')

          @combomethod
          def get_function_by_selector(self, selector):
              def callable_check(fn_abi) -> bool:
                  return encode_hex(function_abi_to_4byte_selector(fn_abi)) == to_4byte_hex(selector)

              fns = find_functions_by_identifier(self.abi, self.tron, self.address, callable_check)
              return get_function_by_identifier(fns, 'selector')

          @combomethod
          def decode_function_input(self, data) -> Tuple[any, dict]:
              data = HexBytes(data)
              selector, params = data[:4], data[4:]
              func = self.get_function_by_selector(selector)
              names = [x['name'] for x in func.abi['inputs']]
              types = [x['type'] for x in func.abi['inputs']]
              decoded = decode_abi(types, params)
              normalized = map_abi_data(BASE_RETURN_NORMALIZERS, types, decoded)
              return func, dict(zip(names, normalized))

          @combomethod
          def find_functions_by_args(self, *args) -> list:
              def callable_check(fn_abi) -> bool:
                  return check_if_arguments_can_be_encoded(fn_abi, args=args, kwargs={})

              return find_functions_by_identifier(
                  self.abi, self.tron, self.address, callable_check
              )

          @combomethod
          def get_function_by_args(self, *args):
              fns = self.find_functions_by_args(*args)
              return get_function_by_identifier(fns, 'args')

  ### Class variables

  `var abi`
  `var address`
  `var bytecode`
  `var bytecode_runtime`
  `var events`
  `var fallback`
  `var functions`
  `var tron`

  ### Static methods

  `def constructor() ‑>`
    Expand source code

        @classmethod
        def constructor(cls) -> any:
            if cls.bytecode is None:
                raise ValueError(
                    "Cannot call constructor on a contract that does not have 'bytecode' associated "
                    "with it"
                )
            return ContractConstructor(cls.tron,
                                       cls.abi,
                                       cls.bytecode)

  `def deploy(cls, **kwargs)`

    Deploy Contract

    This method can also be done in "contract.constructor.transact"

    Deploys a contract. Returns TransactionExtention, which contains an unsigned transaction.

    Example: .. code-block:: python >>> MyContract.deploy( fee_limit=10**9, call_value=0, consume_user_resource_percent=10 )

    ## Args

    `**kwargs`
      Transaction parameters for the deployment

    transaction as a dict

    Expand source code

        @classmethod
        @deprecated_for("contract.constructor.transact")
        def deploy(cls, **kwargs):
            """Deploy Contract

            This method can also be done in "contract.constructor.transact"

            Deploys a contract.
            Returns TransactionExtention, which contains an unsigned transaction.

            Example:
            .. code-block:: python
                >>> MyContract.deploy(
                    fee_limit=10**9,
                    call_value=0,
                    consume_user_resource_percent=10
                )

            Args:
                **kwargs: Transaction parameters for the deployment
                transaction as a dict

            """

            return cls.tron.transaction_builder.create_smart_contract(
                **kwargs,
                abi=cls.abi,
                bytecode=to_hex(cls.bytecode)
            )

  `def factory(tron: , class_name=None, **kwargs) ‑> PropertyCheckingFactory`
    Expand source code

        @classmethod
        def factory(cls, tron: any, class_name=None, **kwargs) -> "PropertyCheckingFactory":

            kwargs['tron'] = tron
            normalizers = {
                'abi': normalize_abi,
                'bytecode': normalize_bytecode,
                'bytecode_runtime': normalize_bytecode,
            }

            contract = PropertyCheckingFactory(
                class_name or cls.__name__,
                (cls,),
                kwargs,
                normalizers=normalizers
            )

            setattr(contract, 'functions', ContractFunctions(contract.abi, contract.tron))
            setattr(contract, 'fallback', Contract.get_fallback_function(contract.abi, contract.tron))

            return contract

  `def get_fallback_function(abi, tron, address=None) ‑>`
    Expand source code

        @staticmethod
        def get_fallback_function(abi, tron, address=None) -> any:
            if abi and fallback_func_abi_exists(abi):
                return ContractFunction.factory(
                    'fallback',
                    tron=tron,
                    contract_abi=abi,
                    address=address,
                    function_identifier=FallbackFn)()

            return NonExistentFallbackFunction()

  ### Methods

  `def all_functions(self) ‑> list`
    Expand source code

        @combomethod
        def all_functions(self) -> list:
            return find_functions_by_identifier(
                self.abi, self.tron, self.address, lambda _: True
            )

  `def decode_function_input(self, data) ‑> Tuple[, dict]`
    Expand source code

        @combomethod
        def decode_function_input(self, data) -> Tuple[any, dict]:
            data = HexBytes(data)
            selector, params = data[:4], data[4:]
            func = self.get_function_by_selector(selector)
            names = [x['name'] for x in func.abi['inputs']]
            types = [x['type'] for x in func.abi['inputs']]
            decoded = decode_abi(types, params)
            normalized = map_abi_data(BASE_RETURN_NORMALIZERS, types, decoded)
            return func, dict(zip(names, normalized))

  `def encodeABI(cls, fn_name, args=None, kwargs=None, data=None) ‑> Union[HexStr, str]`

    Encodes the arguments using the Tron ABI for the contract function that matches the given name and arguments..

    Expand source code

        @combomethod
        def encodeABI(cls, fn_name, args=None, kwargs=None, data=None) -> Union[HexStr, str]:
            """Encodes the arguments using the Tron ABI for the contract function
            that matches the given name and arguments..
            """
            fn_abi, fn_selector, fn_arguments = get_function_info(
                fn_name, contract_abi=cls.abi, args=args, kwargs=kwargs,
            )

            if data is None:
                data = fn_selector

            return encode_abi(cls.tron, fn_abi, fn_arguments, data)

  `def find_functions_by_args(self, *args) ‑> list`
    Expand source code

        @combomethod
        def find_functions_by_args(self, *args) -> list:
            def callable_check(fn_abi) -> bool:
                return check_if_arguments_can_be_encoded(fn_abi, args=args, kwargs={})

            return find_functions_by_identifier(
                self.abi, self.tron, self.address, callable_check
            )

  `def find_functions_by_name(self, fn_name) ‑> list`
    Expand source code

        @combomethod
        def find_functions_by_name(self, fn_name) -> list:
            def callable_check(fn_abi):
                return fn_abi['name'] == fn_name

            return find_functions_by_identifier(
                self.abi, self.tron, self.address, callable_check
            )

  `def get_function_by_args(self, *args)`
    Expand source code

        @combomethod
        def get_function_by_args(self, *args):
            fns = self.find_functions_by_args(*args)
            return get_function_by_identifier(fns, 'args')

  `def get_function_by_name(self, fn_name) ‑>`
    Expand source code

        @combomethod
        def get_function_by_name(self, fn_name) -> any:
            fns = self.find_functions_by_name(fn_name)
            return get_function_by_identifier(fns, 'name')

  `def get_function_by_selector(self, selector)`
    Expand source code

        @combomethod
        def get_function_by_selector(self, selector):
            def callable_check(fn_abi) -> bool:
                return encode_hex(function_abi_to_4byte_selector(fn_abi)) == to_4byte_hex(selector)

            fns = find_functions_by_identifier(self.abi, self.tron, self.address, callable_check)
            return get_function_by_identifier(fns, 'selector')

  `def get_function_by_signature(self, signature) ‑> list`
    Expand source code

        @combomethod
        def get_function_by_signature(self, signature) -> list:
            if ' ' in signature:
                raise ValueError(
                    'Function signature should not contain any spaces. '
                    'Found spaces in input: %s' % signature
                )

            def callable_check(fn_abi):
                return abi_to_signature(fn_abi) == signature

            fns = find_functions_by_identifier(self.abi, self.tron, self.address, callable_check)
            return get_function_by_identifier(fns, 'signature')

`class ContractConstructor (tron, abi, bytecode)`

  Class for contract constructor API.

  Expand source code

      class ContractConstructor:
          """
          Class for contract constructor API.
          """

          def __init__(self, tron, abi, bytecode):
              self.tron = tron
              self.abi = abi
              self.bytecode = bytecode

          @staticmethod
          def check_forbidden_keys_in_transaction(transaction, forbidden_keys=None):
              keys_found = set(transaction.keys()) & set(forbidden_keys)
              if keys_found:
                  raise ValueError("Cannot set {} in transaction".format(', '.join(keys_found)))

          @combomethod
          def transact(self, **kwargs):
              """Deploy Contract

              Deploys a contract.
              Returns TransactionExtention, which contains an unsigned transaction.

              Args:
                  **kwargs: Additional options to send
              """

              return self.tron.transaction_builder.create_smart_contract(
                  **kwargs,
                  abi=self.abi,
                  bytecode=to_hex(self.bytecode)
              )

  ### Static methods

  `def check_forbidden_keys_in_transaction(transaction, forbidden_keys=None)`
    Expand source code

        @staticmethod
        def check_forbidden_keys_in_transaction(transaction, forbidden_keys=None):
            keys_found = set(transaction.keys()) & set(forbidden_keys)
            if keys_found:
                raise ValueError("Cannot set {} in transaction".format(', '.join(keys_found)))

  ### Methods

  `def transact(self, **kwargs)`

    Deploy Contract

    Deploys a contract. Returns TransactionExtention, which contains an unsigned transaction.

    ## Args

    `**kwargs`
      Additional options to send
    Expand source code

        @combomethod
        def transact(self, **kwargs):
            """Deploy Contract

            Deploys a contract.
            Returns TransactionExtention, which contains an unsigned transaction.

            Args:
                **kwargs: Additional options to send
            """

            return self.tron.transaction_builder.create_smart_contract(
                **kwargs,
                abi=self.abi,
                bytecode=to_hex(self.bytecode)
            )

`class ContractFunction (abi=None)`

  Base class for contract functions

  Expand source code

      class ContractFunction:
          """Base class for contract functions"""
          address = None
          function_identifier = None
          tron = None
          contract_abi = None
          abi = None
          transaction = None
          arguments = None

          def __init__(self, abi=None):
              self.abi = abi
              self.fn_name = type(self).__name__

          def __call__(self, *args, **kwargs):
              clone = copy.copy(self)
              if args is None:
                  clone.args = tuple()
              else:
                  clone.args = args

              if kwargs is None:
                  clone.kwargs = {}
              else:
                  clone.kwargs = kwargs
              clone._set_function_info()
              return clone

          def _set_function_info(self):
              if not self.abi:
                  self.abi = find_matching_fn_abi(
                      self.contract_abi,
                      self.function_identifier,
                      self.args,
                      self.kwargs
                  )
              if self.function_identifier is FallbackFn:
                  self.selector = encode_hex(b'')
              elif is_text(self.function_identifier):
                  self.selector = encode_hex(function_abi_to_4byte_selector(self.abi))
              else:
                  raise TypeError("Unsupported function identifier")

              self.arguments = merge_args_and_kwargs(self.abi, self.args, self.kwargs)

          @classmethod
          def factory(cls, class_name, **kwargs):
              return PropertyCheckingFactory(class_name, (cls,), kwargs)(kwargs.get('abi'))

          def __repr__(self):
              if self.abi:
                  _repr = '<Function %s' % abi_to_signature(self.abi)
                  if self.arguments is not None:
                      _repr += ' bound to %r' % (self.arguments,)
                  return _repr + '>'
              return '<Function %s>' % self.fn_name

  ### Class variables

  `var abi`
  `var address`
  `var arguments`
  `var contract_abi`
  `var function_identifier`
  `var transaction`
  `var tron`

  ### Static methods

  `def factory(class_name, **kwargs)`
    Expand source code

        @classmethod
        def factory(cls, class_name, **kwargs):
            return PropertyCheckingFactory(class_name, (cls,), kwargs)(kwargs.get('abi'))

`class ContractFunctions (_abi, tron, address=None)`

  Class containing contract function objects

  Expand source code

      class ContractFunctions:
          """
          Class containing contract function objects
          """

          def __init__(self, _abi, tron, address=None):
              if _abi:
                  self._functions = filter_by_type('function', _abi)
                  for func in self._functions:
                      setattr(self, func['name'],
                              ContractFunction.factory(
                                  func['name'],
                                  tron=tron,
                                  contract_abi=_abi,
                                  address=address,
                                  function_identifier=func['name']))
                  self.abi = _abi

          def get_abi_by_name(self, func_name: str) -> dict:
              """Find the correct function abi for the name"""
              t = filter_by_name(func_name, self.abi)
              if len(t) > 0:
                  return t[0]
              raise NoABIFunctionsFound(
                  "The abi for this contract contains no function definitions. ",
                  "Are you sure you provided the correct call name from the abi?"
              )

          def print_functions(self):
              """only for testing, list all the functions that can be called. """
              for func in self._functions:
                  if func['type'] == 'function':
                      if func['stateMutability'] in ['pure', 'view']:
                          printdebugfunc('read', func)
                      if func['stateMutability'] in ['nonpayable']:
                          printdebugfunc('write', func)

                  if func['type'] == 'constructor':
                      printdebugfunc('constructor', func)
                  print("=====")
                  print(func)

          def __iter__(self):
              if not hasattr(self, '_functions') or not self._functions:
                  return

              for func in self._functions:
                  yield func['name']

          def __getattr__(self, function_name):
              if '_functions' not in self.__dict__:
                  raise NoABIFunctionsFound(
                      "The abi for this contract contains no function definitions. ",
                      "Are you sure you provided the correct contract abi?"
                  )
              elif function_name not in self.__dict__['_functions']:
                  raise MismatchedABI(
                      "The function '{}' was not found in this contract's abi. ".format(function_name),
                      "Are you sure you provided the correct contract abi?"
                  )
              else:
                  return super().__getattribute__(function_name)

          def __getitem__(self, function_name):
              return getattr(self, function_name)

  ### Methods

  `def get_abi_by_name(self, func_name: str) ‑> dict`

    Find the correct function abi for the name

    Expand source code

        def get_abi_by_name(self, func_name: str) -> dict:
            """Find the correct function abi for the name"""
            t = filter_by_name(func_name, self.abi)
            if len(t) > 0:
                return t[0]
            raise NoABIFunctionsFound(
                "The abi for this contract contains no function definitions. ",
                "Are you sure you provided the correct call name from the abi?"
            )

  `def print_functions(self)`

    only for testing, list all the functions that can be called.

    Expand source code

        def print_functions(self):
            """only for testing, list all the functions that can be called. """
            for func in self._functions:
                if func['type'] == 'function':
                    if func['stateMutability'] in ['pure', 'view']:
                        printdebugfunc('read', func)
                    if func['stateMutability'] in ['nonpayable']:
                        printdebugfunc('write', func)

                if func['type'] == 'constructor':
                    printdebugfunc('constructor', func)
                print("=====")
                print(func)

`class NonExistentFallbackFunction`
  Expand source code

      class NonExistentFallbackFunction:
          @staticmethod
          def _raise_exception():
              raise FallbackNotFound("No fallback function was found in the contract ABI.")

          def __getattr__(self, attr):
              return NonExistentFallbackFunction._raise_exception