Exemple #1
0
    def list_tokens(self, limit=0, offset=0):
        """Query the list of Tokens with pagination

        Args:
            limit (int): index of the starting Token
            offset (int): number of Tokens expected to be returned

        Returns:
            List of Tokens

        """
        if not is_integer(limit) or (limit and offset < 1):
            raise InvalidTronError('Invalid limit provided')

        if not is_integer(offset) or offset < 0:
            raise InvalidTronError('Invalid offset provided')

        if not limit:
            return self.tron.manager.request('/wallet/getassetissuelist').get(
                'assetIssue')

        return self.tron.manager.request('/wallet/getpaginatedassetissuelist',
                                         {
                                             'limit': int(limit),
                                             'offset': int(offset)
                                         })
Exemple #2
0
    def deploy(cls, **kwargs):
        """Deploy Contract

        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

        """
        if not cls.bytecode:
            raise ValueError(
                "Cannot deploy a contract that does not have 'bytecode' associated "
                "with it")

        # Maximum TRX consumption, measured in SUN (1 TRX = 1,000,000 SUN).
        fee_limit = kwargs.setdefault('fee_limit', 0)
        # The same as User Pay Ratio.
        # The percentage of resources specified for users who use this contract.
        # This field accepts integers between [0, 100].
        user_fee_percentage = kwargs.setdefault(
            'consume_user_resource_percent', 0)
        # Amount of TRX transferred with this transaction, measured in SUN (1TRX = 1,000,000 SUN)
        call_value = kwargs.setdefault('call_value', 0)
        # Contract owner address, converted to a hex string
        owner_address = kwargs.setdefault('owner_address',
                                          cls.tron.default_address.hex)

        # We write all the results in one object
        transaction = dict(**kwargs)
        # Smart Contract's Application Binary Interface
        transaction.setdefault('abi', cls.abi)
        # The compiled contract's identifier, used to interact with the Virtual Machine.
        transaction.setdefault('bytecode', to_hex(cls.bytecode))

        if not is_integer(fee_limit) or fee_limit <= 0 or \
                fee_limit > 10 ** 9:
            raise ValueError('Invalid fee limit provided')

        if not is_integer(call_value) or call_value < 0:
            raise ValueError('Invalid call value provided')

        if not is_integer(user_fee_percentage) or user_fee_percentage < 0 or \
                user_fee_percentage > 100:
            raise ValueError('Invalid user fee percentage provided')

        if not cls.tron.isAddress(owner_address):
            raise InvalidAddress('Invalid issuer address provided')

        return cls.tron.manager.request('/wallet/deploycontract', transaction)
Exemple #3
0
    def transact(self, **kwargs):
        """Deploy Contract

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

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

        # Maximum TRX consumption, measured in SUN (1 TRX = 1,000,000 SUN).
        fee_limit = kwargs.setdefault('fee_limit', 1000000000)
        # The same as User Pay Ratio.
        # The percentage of resources specified for users who use this contract.
        # This field accepts integers between [0, 100].
        user_fee_percentage = kwargs.setdefault(
            'consume_user_resource_percent', 0)
        # Amount of TRX transferred with this transaction, measured in SUN (1TRX = 1,000,000 SUN)
        call_value = kwargs.setdefault('call_value', 0)
        # Contract owner address, converted to a hex string
        owner_address = kwargs.setdefault('owner_address',
                                          self.tron.default_address.hex)
        # The max energy which will be consumed by the owner
        # in the process of excution or creation of the contract,
        # is an integer which should be greater than 0.
        origin_energy_limit = kwargs.setdefault('origin_energy_limit',
                                                10000000)

        # The compiled contract's identifier, used to interact with the Virtual Machine.
        bytecode = to_hex(self.bytecode)

        if not is_integer(
                fee_limit) or fee_limit <= 0 or fee_limit > 1000000000:
            raise ValueError('Invalid fee limit provided')

        if not is_integer(call_value) or call_value < 0:
            raise ValueError('Invalid call value provided')

        if not is_integer(user_fee_percentage) or user_fee_percentage < 0 or \
                user_fee_percentage > 100:
            raise ValueError('Invalid user fee percentage provided')

        if not is_integer(origin_energy_limit) or origin_energy_limit < 0:
            return ValueError('Invalid origin_energy_limit provided')

        if not self.tron.isAddress(owner_address):
            raise InvalidAddress('Invalid issuer address provided')

        # We write all the results in one object
        transact_transaction = dict(**kwargs)
        transact_transaction.setdefault(
            'owner_address', self.tron.address.to_hex(owner_address))
        transact_transaction.setdefault('abi', self.abi)
        transact_transaction.setdefault('bytecode', bytecode)

        return self.tron.manager.request('/wallet/deploycontract',
                                         transact_transaction)
Exemple #4
0
    def get_event_result(self,
                         contract_address=None,
                         since=0,
                         event_name=None,
                         block_number=None,
                         size=20,
                         page=1):
        """Will return all events matching the filters.

        Args:
            contract_address (str): Address to query for events.
            since (int): Filter for events since certain timestamp.
            event_name (str): Name of the event to filter by.
            block_number (str): Specific block number to query
            size (int): size
            page (int): page str
        """

        if not self.isAddress(contract_address):
            raise InvalidTronError('Invalid contract address provided')

        if event_name and not contract_address:
            raise TronError('Usage of event name filtering requires a contract address')

        if block_number and event_name is None:
            raise TronError('Usage of block number filtering requires an event name')

        if not is_integer(page):
            raise ValueError('Invalid size provided')

        if not is_integer(since):
            raise ValueError('Invalid sinceTimestamp provided')

        if size > 200:
            raise ValueError('Defaulting to maximum accepted size: 200')

        route_params = []

        if contract_address:
            route_params.append(contract_address)

        if event_name:
            route_params.append(event_name)

        if block_number:
            route_params.append(block_number)

        route = '/'.join(route_params)

        return self.manager.request("/event/contract/{0}?since={1}&size={2}&page={3}"
                                    .format(route, since, size, page), method='get')
Exemple #5
0
    def get_event_result(self, **kwargs):
        """Will return all events matching the filters.

        Args:
            kwargs (any): List parameters
        """

        # Check the most necessary parameters
        contract_address = kwargs.setdefault('contract_address',
                                             self.default_address.hex)
        event_name = kwargs.setdefault('event_name', 'Notify')
        since_timestamp = kwargs.setdefault('since_timestamp', 0)
        block_number = kwargs.setdefault('block_number', '')
        size = kwargs.setdefault('size', 20)
        page = kwargs.setdefault('page', 1)

        if not self.isAddress(contract_address):
            raise InvalidTronError('Invalid contract address provided')

        if event_name and not contract_address:
            raise TronError(
                'Usage of event name filtering requires a contract address')

        if block_number and event_name is None:
            raise TronError(
                'Usage of block number filtering requires an event name')

        if not is_integer(page):
            raise ValueError('Invalid size provided')

        if not is_integer(since_timestamp):
            raise ValueError('Invalid sinceTimestamp provided')

        # If the size exceeds 200, displays an error
        if size > 200:
            raise ValueError('Defaulting to maximum accepted size: 200')

        # We collect all parameters in one array
        route_params = []
        if contract_address:
            route_params.append(contract_address)
        if event_name:
            route_params.append(event_name)
        if block_number:
            route_params.append(block_number)

        route = '/'.join(route_params)
        return self.manager.request(
            "/event/contract/{0}?since={1}&size={2}&page={3}".format(
                route, since_timestamp, size, page),
            method='get')
Exemple #6
0
def validate_abi_value(abi_type, value):
    """
    Helper function for validating a value against the expected abi_type
    Note: abi_type 'bytes' must either be python3 'bytes' object or ''
    """
    if is_array_type(abi_type) and is_list_like(value):
        # validate length
        specified_length = length_of_array_type(abi_type)
        if specified_length is not None:
            if specified_length < 1:
                raise TypeError(
                    "Invalid abi-type: {abi_type}. Length of fixed sized arrays"
                    "must be greater than 0.".format(abi_type=abi_type))
            if specified_length != len(value):
                raise TypeError(
                    "The following array length does not the length specified"
                    "by the abi-type, {abi_type}: {value}".format(
                        abi_type=abi_type, value=value))

        # validate sub_types
        sub_type = sub_type_of_array_type(abi_type)
        for v in value:
            validate_abi_value(sub_type, v)
        return
    elif is_bool_type(abi_type) and is_boolean(value):
        return
    elif is_uint_type(abi_type) and is_integer(value) and value >= 0:
        return
    elif is_int_type(abi_type) and is_integer(value):
        return
    elif is_address_type(abi_type):
        is_address(value)
        return
    elif is_bytes_type(abi_type):
        if is_bytes(value):
            return
        elif is_string(value):
            if is_0x_prefixed(value):
                return
            else:
                raise TypeError(
                    "ABI values of abi-type 'bytes' must be either"
                    "a python3 'bytes' object or an '0x' prefixed string.")
    elif is_string_type(abi_type) and is_string(value):
        return

    raise TypeError(
        "The following abi value is not a '{abi_type}': {value}".format(
            abi_type=abi_type, value=value))
    def update_setting(self,
                       contract_address,
                       user_fee_percentage,
                       owner_address=None):
        """Update userFeePercentage.

        Args:
            contract_address (str): the address of the contract to be modified
            user_fee_percentage (int): the percentage of resources specified for users using this contract
            owner_address (str): is the address of the creator

        Returns:
            Contains unsigned transaction Transaction
        """

        if owner_address is None:
            owner_address = self.tron.default_address.hex

        if not self.tron.isAddress(owner_address):
            raise InvalidAddress('Invalid owner_address provided')

        if not self.tron.isAddress(contract_address):
            raise InvalidAddress('Invalid contract_address provided')

        if not is_integer(user_fee_percentage) or user_fee_percentage < 0 or \
                user_fee_percentage > 100:
            raise ValueError('Invalid user_fee_percentage provided')

        return self.tron.manager.request('wallet/updatesetting', {
            'owner_address': self.tron.address.to_hex(owner_address),
            'contract_address': self.tron.address.to_hex(contract_address),
            'consume_user_resource_percent': user_fee_percentage
        })
Exemple #8
0
    def vote_proposal(self, proposal_id, has_approval, voter_address=None):
        """Proposal approval

        Args:
            proposal_id (int): proposal id
            has_approval (bool): Approved
            voter_address (str): Approve address

        """

        # If the address of the sender is not specified, we prescribe the default
        if voter_address is None:
            voter_address = self.tron.default_address.hex

        if not self.tron.isAddress(voter_address):
            raise TronError('Invalid voter_address address provided')

        if not is_integer(proposal_id) or proposal_id < 0:
            raise TronError('Invalid proposal_id provided')

        if not is_boolean(has_approval):
            raise TronError('Invalid has_approval provided')

        return self.tron.manager.request(
            '/wallet/proposalapprove', {
                'owner_address': self.tron.address.to_hex(voter_address),
                'proposal_id': int(proposal_id),
                'is_add_approval': bool(has_approval)
            })
    def update_energy_limit(self,
                            contract_address,
                            origin_energy_limit,
                            owner_address=None):
        """Update energy limit.

        Args:
            contract_address (str): The address of the contract to be modified
            origin_energy_limit (int): The maximum energy set by the creator that is created
            owner_address (str): Is the address of the creator

        Returns:
            Contains unsigned transaction Transaction
        """

        if owner_address is None:
            owner_address = self.tron.default_address.hex

        if not self.tron.isAddress(owner_address):
            raise InvalidAddress('Invalid owner_address provided')

        if not self.tron.isAddress(contract_address):
            raise InvalidAddress('Invalid contractAddress provided')

        if not is_integer(origin_energy_limit) or origin_energy_limit < 0 or \
                origin_energy_limit > 10000000:
            raise ValueError('Invalid originEnergyLimit  provided')

        return self.tron.manager.request('wallet/updateenergylimit', {
            'owner_address': self.tron.address.to_hex(owner_address),
            'contract_address': self.tron.address.to_hex(contract_address),
            'origin_energy_limit': origin_energy_limit
        })
Exemple #10
0
    def freeze_balance(self, amount, duration, resource, account=None):
        """
        Freezes an amount of TRX.
        Will give bandwidth OR Energy and TRON Power(voting rights)
        to the owner of the frozen tokens.

        Args:
            amount (int): number of frozen trx
            duration (int): duration in days to be frozen
            resource (str): type of resource, must be either "ENERGY" or "BANDWIDTH"
            account (str): address that is freezing trx account

        """

        # If the address of the sender is not specified, we prescribe the default
        if account is None:
            account = self.tron.default_address.hex

        if resource not in (
                'BANDWIDTH',
                'ENERGY',
        ):
            raise InvalidTronError(
                'Invalid resource provided: Expected "BANDWIDTH" or "ENERGY"')

        if not is_integer(amount) or amount <= 0:
            raise InvalidTronError('Invalid amount provided')

        if not is_integer(duration) or duration < 3:
            raise InvalidTronError(
                'Invalid duration provided, minimum of 3 days')

        if not self.tron.isAddress(account):
            raise InvalidTronError('Invalid address provided')

        response = self.tron.manager.request(
            '/wallet/freezebalance', {
                'owner_address': self.tron.address.to_hex(account),
                'frozen_balance': self.tron.toSun(amount),
                'frozen_duration': int(duration),
                'resource': resource
            })

        if 'Error' in response:
            raise TronError(response['Error'])

        return response
Exemple #11
0
    def default_block(self, block_id):
        """Sets the default block used as a reference for all future calls."""
        if block_id in ('latest', 'earliest', 0):
            self._default_block = block_id
            return

        if not is_integer(block_id) or not block_id:
            raise ValueError('Invalid block ID provided')

        self._default_block = abs(block_id)
Exemple #12
0
    def get_block_range(self, start, end):
        """Query a range of blocks by block height

        Args:
            start (int): starting block height, including this block
            end (int): ending block height, excluding that block

        """
        if not is_integer(start) or start < 0:
            raise InvalidTronError('Invalid start of range provided')

        if not is_integer(end) or end <= start:
            raise InvalidTronError('Invalid end of range provided')

        response = self.tron.manager.request('/wallet/getblockbylimitnext', {
            'startNum': int(start),
            'endNum': int(end) + 1
        }, 'post')

        return response.get('block')
Exemple #13
0
def select_method_for_block(value, if_hash, if_number):
    if isinstance(value, bytes):
        return if_hash
    elif is_hex_encoded_block_hash(value):
        return if_hash
    elif is_integer(value) and (0 <= value < 2**256):
        return if_number
    elif is_hex_encoded_block_number(value):
        return if_number
    else:
        raise ValueError(
            "Value did not match any of the recognized block identifiers: {0}".
            format(value))
Exemple #14
0
    def get_latest_blocks(self, num=1):
        """Query the latest blocks

        Args:
            num (int): the number of blocks to query

        """
        if not is_integer(num) or num <= 0:
            raise InvalidTronError('Invalid limit provided')

        response = self.tron.manager.request('/wallet/getblockbylatestnum',
                                             {'num': num})

        return response.get('block')
Exemple #15
0
    def get_block_by_number(self, block_id):
        """Query block by height

        Args:
            block_id (int): height of the block

        Returns:
            Block object

        """
        if not is_integer(block_id) or block_id < 0:
            raise InvalidTronError('Invalid block number provided')

        return self.full_node.request('/wallet/getblockbynum',
                                      {'num': int(block_id)}, 'post')
Exemple #16
0
def to_text(primitive=None, hexstr=None, text=None):
    assert_one_val(primitive, hexstr=hexstr, text=text)

    if hexstr is not None:
        return to_bytes(hexstr=hexstr).decode('utf-8')
    elif text is not None:
        return text
    elif isinstance(primitive, str):
        return to_text(hexstr=primitive)
    elif isinstance(primitive, bytes):
        return primitive.decode('utf-8')
    elif is_integer(primitive):
        byte_encoding = int_to_big_endian(primitive)
        return to_text(byte_encoding)
    raise TypeError("Expected an int, bytes or hexstr.")
Exemple #17
0
def to_bytes(primitive=None, hexstr=None, text=None):
    assert_one_val(primitive, hexstr=hexstr, text=text)

    if is_boolean(primitive):
        return b'\x01' if primitive else b'\x00'
    elif isinstance(primitive, bytes):
        return primitive
    elif is_integer(primitive):
        return to_bytes(hexstr=to_hex(primitive))
    elif hexstr is not None:
        if len(hexstr) % 2:
            hexstr = '0x0' + remove_0x_prefix(hexstr)
        return decode_hex(hexstr)
    elif text is not None:
        return text.encode('utf-8')
    raise TypeError("expected an int in first arg, or keyword of hexstr or text")
Exemple #18
0
    def get_transaction_from_block(self, block: Any, index: int = 0):
        """Get transaction details from Block

        Args:
            block (Any): Number or Hash Block
            index (int) Position

        """
        if not is_integer(index) or index < 0:
            raise InvalidTronError('Invalid transaction index provided')

        transactions = self.get_block(block).get('transactions')
        if not transactions or len(transactions) < index:
            raise TronError('Transaction not found in block')

        return transactions[index]
Exemple #19
0
    def get_latest_blocks(self, limit=1):
        """Query the latest blocks

        Args:
            limit (int): the number of blocks to query

        Returns:
            A list of Block Objects

        """
        if not is_integer(limit) or limit <= 0:
            raise InvalidTronError('Invalid limit provided')

        response = self.full_node.request('/wallet/getblockbylatestnum',
                                          {'limit': limit}, 'post')

        return response['block']
    def vote(self, votes: List[Tuple[str, int]], voter_address: str = None):
        """Vote
        Vote on the super representative

        Args:
            votes (dict): dictionary of SR address : vote count key-value pair
            voter_address: voter address

        Examples:
            >>> from tronapi import Tron
            >>> data = [
            >>>     ('TRJpw2uqohP7FUmAEJgt57wakRn6aGQU6Z', 1)
            >>> ]
            >>> tron = Tron()
            >>> tron.transaction.vote(data)

        """
        if voter_address is None:
            voter_address = self.tron.default_address.hex

        _view_vote = []

        # We create a cycle to check all the received data for voting.
        for sr_address, vote_count in votes:
            if not self.tron.isAddress(sr_address):
                raise InvalidAddress('Invalid SR address provided: ' +
                                     sr_address)

            if not is_integer(vote_count) or vote_count <= 0:
                raise ValueError('Invalid vote count provided for SR: ' +
                                 sr_address)

            _view_vote.append({
                'vote_address':
                self.tron.address.to_hex(sr_address),
                'vote_count':
                int(vote_count)
            })

        return self.tron.manager.request(
            '/wallet/votewitnessaccount', {
                'owner_address': self.tron.address.to_hex(voter_address),
                'votes': _view_vote
            })
    def vote_proposal(self, proposal_id, has_approval, voter_address):
        """Proposal approval

        Args:
            proposal_id (int): proposal id
            has_approval (bool): Approved
            voter_address (str): Approve address

        """
        if not self.tron.isAddress(voter_address):
            raise TronError('Invalid voter_address address provided')

        if not is_integer(proposal_id) or proposal_id < 0:
            raise TronError('Invalid proposal_id provided')

        if not is_boolean(has_approval):
            raise TronError('Invalid has_approval provided')

        return self.tron.manager.request('/wallet/proposalapprove', {
            'owner_address': self.tron.address.to_hex(voter_address),
            'proposal_id': int(proposal_id),
            'is_add_approval': bool(has_approval)
        })
    def trigger_smart_contract(self, contract_address,
                               function_selector,
                               fee_limit: int = 1000000000,
                               call_value: int = 0,
                               parameters=None,
                               issuer_address=None
                               ):
        """Trigger Smart Contract (Beta Version)
        Calls a function on a contract

        Args:
            contract_address (str): Contract address, converted to a hex string
            function_selector (str): Function signature. No spaces.
            fee_limit (int): Maximum TRX consumption, measured in SUN(1TRX = 1,000,000SUN)
            call_value (int): Amount of TRX transferred with this transaction, measured in SUN(1TRX = 1,000,000SUN)
            parameters (any): Call the virtual machine format of the parameter [1, 2],
                                use the js tool provided by remix, convert the parameter array [1, 2]
                                called by the contract caller into
                                the parameter format required by the virtual machine.

            issuer_address (str): address that is trigger the contract

        Examples:
            >>> tron = Tron()
            >>> tron.transaction_builder.trigger_smart_contract(
            >>> '413c8143e98b3e2fe1b1a8fb82b34557505a752390',
            >>> 'set(uint256,uint256)',
            >>> 30000,
            >>> 0,
            >>> [
            >>>     {'type': 'int256', 'value': 1},
            >>>     {'type': 'int256', 'value': 1}
            >>> ])

        Returns:
            TransactionExtention, TransactionExtention contains unsigned Transaction
        """

        if parameters is None:
            parameters = []

        if issuer_address is None:
            issuer_address = self.tron.default_address.hex

        if not self.tron.isAddress(contract_address):
            raise InvalidAddress('Invalid contract address provided')

        if not is_string(function_selector):
            raise ValueError('Invalid function selector provided')

        if not is_integer(call_value) or call_value < 0:
            raise ValueError('Invalid call value provided')

        if not is_integer(fee_limit) or fee_limit <= 0 or fee_limit > 1000000000:
            raise ValueError('Invalid fee limit provided')

        if len(parameters) > 0:
            types = []
            values = []
            for abi in parameters:
                if 'type' not in abi or not is_string(abi['type']):
                    raise ValueError('Invalid parameter type provided: ' + abi['type'])

                if abi['type'] == 'address':
                    abi['value'] = self.tron.address.to_hex(abi['value']).replace('41', '0x', 2)

                types.append(abi['type'])
                values.append(abi['value'])

            try:
                parameters = encode_hex(encode_abi(types, values)).replace('0x', '', 2)
            except ValueError as ex:
                print(ex)

        else:
            parameters = ''

        return self.tron.manager.request('/wallet/triggersmartcontract', {
            'contract_address': self.tron.address.to_hex(contract_address),
            'owner_address': self.tron.address.to_hex(issuer_address),
            'function_selector': function_selector,
            'fee_limit': int(fee_limit),
            'call_value': int(call_value),
            'parameter': parameters
        })
    def create_smart_contract(self, **kwargs):
        """Deploy Contract

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

        Example:
        .. code-block:: python
            >>> from tronapi import Tron
            >>>
            >>> tron = Tron()
            >>> tron.transaction_builder.create_smart_contract(
            >>>    fee_limit=10**9,
            >>>    call_value=0,
            >>>    consume_user_resource_percent=10
            >>> )

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

        """

        if 'bytecode' not in kwargs:
            raise ValueError(
                "Cannot deploy a contract that does not have 'bytecode' associated "
                "with it")

        # Maximum TRX consumption, measured in SUN (1 TRX = 1,000,000 SUN).
        fee_limit = kwargs.setdefault('fee_limit', 0)
        # The same as User Pay Ratio.
        # The percentage of resources specified for users who use this contract.
        # This field accepts integers between [0, 100].
        user_fee_percentage = kwargs.setdefault(
            'consume_user_resource_percent', 0)
        # Amount of TRX transferred with this transaction, measured in SUN (1TRX = 1,000,000 SUN)
        call_value = kwargs.setdefault('call_value', 0)
        # Contract owner address, converted to a hex string
        owner_address = kwargs.setdefault('owner_address',
                                          self.tron.default_address.hex)
        # The max energy which will be consumed by the owner
        # in the process of excution or creation of the contract,
        # is an integer which should be greater than 0.
        origin_energy_limit = kwargs.setdefault('origin_energy_limit',
                                                10000000)

        if not is_hex(kwargs.get('bytecode')):
            raise ValueError('Invalid bytecode provided')

        if not is_integer(fee_limit) or fee_limit <= 0 or \
                fee_limit > 1000000000:
            raise ValueError('Invalid fee limit provided')

        if not is_integer(call_value) or call_value < 0:
            raise ValueError('Invalid call value provided')

        if not is_integer(user_fee_percentage) or user_fee_percentage < 0 or \
                user_fee_percentage > 100:
            raise ValueError('Invalid user fee percentage provided')

        if not is_integer(origin_energy_limit) or origin_energy_limit < 0:
            return ValueError('Invalid origin_energy_limit provided')

        if not self.tron.isAddress(owner_address):
            raise InvalidAddress('Invalid issuer address provided')

        # We write all the results in one object
        transaction = dict(**kwargs)
        transaction.setdefault('owner_address',
                               self.tron.address.to_hex(owner_address))

        return self.tron.manager.request('/wallet/deploycontract', transaction)
    def create_token(self, **kwargs):
        """Issue Token

        Issuing a token on the TRON Protocol can be done by anyone
        who has at least 1024 TRX in their account.
        When a token is issued it will be shown on the token overview page.
        Users can then participate within the issuing time and exchange their
        TRX for tokens.After issuing the token your account will
        receive the amount of tokens equal to the total supply.
        When other users exchange their TRX for tokens then the tokens
        will be withdrawn from your account and you will receive
        TRX equal to the specified exchange rate.


        Args:
            **kwargs: Fill in the required parameters

        Examples:

            >>> start_func = datetime.now()
            >>> start = int(start_func.timestamp() * 1000)
            >>>
            >>> end_func = datetime.now() + timedelta(days=2)
            >>> end = int(end_func.timestamp() * 1000)
            >>>
            >>> opt = {
            >>>     'name': 'Tron',
            >>>     'abbreviation': 'TRX',
            >>>     'description': 'Hello World',
            >>>     'url': 'https://github.com',
            >>>     'totalSupply': 25000000,
            >>>     'frozenAmount': 1,
            >>>     'frozenDuration': 2,
            >>>     'freeBandwidth': 10000,
            >>>     'freeBandwidthLimit': 10000,
            >>>     'saleStart': start,
            >>>     'saleEnd': end,
            >>>     'voteScore': 1
            >>> }

        """
        issuer_address = kwargs.setdefault(
            'issuer_address', self.tron.default_address.hex
        )

        if not self.tron.isAddress(issuer_address):
            raise TronError('Invalid issuer address provided')

        total_supply = kwargs.setdefault('totalSupply', 0)
        trx_ratio = kwargs.setdefault('trxRatio', 1)
        token_ratio = kwargs.setdefault('tokenRatio', 1)
        sale_start = kwargs.setdefault(
            'saleStart', START_DATE
        )
        free_bandwidth = kwargs.setdefault('freeBandwidth', 0)
        free_bandwidth_limit = kwargs.setdefault('freeBandwidthLimit', 0)
        frozen_amount = kwargs.setdefault('frozenAmount', 0)
        frozen_duration = kwargs.setdefault('frozenDuration', 0)
        vote_score = kwargs.setdefault('voteScore', 0)

        if not is_string(kwargs.get('name')):
            raise ValueError('Invalid token name provided')

        if not is_string(kwargs.get('abbreviation')):
            raise ValueError('Invalid token abbreviation provided')

        if not is_integer(total_supply) or total_supply <= 0:
            raise ValueError('Invalid supply amount provided')

        if not is_integer(trx_ratio) or trx_ratio <= 0:
            raise ValueError('TRX ratio must be a positive integer')

        if not is_integer(token_ratio) or token_ratio <= 0:
            raise ValueError('Token ratio must be a positive integer')

        if not is_integer(vote_score) or vote_score <= 0:
            raise ValueError('Invalid vote score provided')

        if not is_integer(sale_start) or sale_start < START_DATE:
            raise ValueError('Invalid sale start timestamp provided')

        if not is_integer(kwargs.get('saleEnd')) or \
                kwargs.get('saleEnd') <= sale_start:
            raise ValueError('Invalid sale end timestamp provided')

        if not is_string(kwargs.get('description')):
            raise ValueError('Invalid token description provided')

        if not is_valid_url(kwargs.get('url')):
            raise ValueError('Invalid token url provided')

        if not is_integer(free_bandwidth) or free_bandwidth < 0:
            raise ValueError('Invalid free bandwidth amount provided')

        if not is_integer(free_bandwidth_limit) or free_bandwidth_limit < 0 \
                or (free_bandwidth and not free_bandwidth_limit):
            raise ValueError('Invalid free bandwidth limit provided')

        if not is_integer(frozen_amount) or frozen_amount < 0 \
                or (not frozen_duration and frozen_amount):
            raise ValueError('Invalid frozen supply provided')

        if not is_integer(frozen_duration) or frozen_duration < 0 \
                or (frozen_duration and not frozen_amount):
            raise ValueError('Invalid frozen duration provided')

        frozen_supply = {
            'frozen_amount': int(frozen_amount),
            'frozen_days': int(frozen_duration)
        }

        response = self.tron.manager.request('/wallet/createassetissue', {
            'owner_address': self.tron.address.to_hex(issuer_address),
            'name': self.tron.toHex(text=kwargs.get('name')),
            'abbr': self.tron.toHex(text=kwargs.get('abbreviation')),
            'description': self.tron.toHex(text=kwargs.get('description')),
            'url': self.tron.toHex(text=kwargs.get('url')),
            'total_supply': int(total_supply),
            'trx_num': int(trx_ratio),
            'num': int(token_ratio),
            'start_time': int(sale_start),
            'end_time': int(kwargs.get('saleEnd')),
            'free_asset_net_limit': int(free_bandwidth),
            'public_free_asset_net_limit': int(free_bandwidth_limit),
            'frozen_supply': frozen_supply,
            'vote_score': vote_score
        })

        return response