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): validate_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_account(self, account_name, account: str = None): """Modify account name Note: Username is allowed to edit only once. Args: account_name (str): name of the account account (str): address Returns: modified Transaction Object """ # If the address of the sender is not specified, we prescribe the default if account is None: account = self.tron.default_address.hex if not is_string(account_name): raise ValueError('Name must be a string') if not self.tron.isAddress(account): raise TronError('Invalid origin address provided') response = self.tron.manager.request( '/wallet/updateaccount', { 'account_name': self.tron.toHex(text=account_name), 'owner_address': self.tron.address.to_hex(account) }) return response
def is_hex_encoded_block_number(value): if not is_string(value): return False elif is_hex_encoded_block_hash(value): return False try: value_as_int = int(value, 16) except ValueError: return False return 0 <= value_as_int < 2**256
def map_collection(func, collection): """ Apply func to each element of a collection, or value of a dictionary. If the value is not a collection, return it unmodified """ datatype = type(collection) if isinstance(collection, Mapping): return datatype((key, func(val)) for key, val in collection.items()) if is_string(collection): return collection elif isinstance(collection, Iterable): return datatype(map(func, collection)) else: return collection
def send_token(self, to, amount, token_id, account=None): """Transfer Token Args: to (str): is the recipient address amount (int): is the amount of token to transfer. must be integer instead of float token_id (any): Token Name and id account: (str): is the address of the withdrawal account Returns: Token transfer Transaction raw data """ # If the address of the sender is not specified, we prescribe the default if account is None: account = self.tron.default_address.hex if not self.tron.isAddress(to): raise InvalidTronError('Invalid recipient address provided') if not isinstance(amount, int) or amount <= 0: raise InvalidTronError('Invalid amount provided') if not token_id: raise InvalidTronError('Invalid token ID provided') if not self.tron.isAddress(account): raise InvalidTronError('Invalid origin address provided') _to = self.tron.address.to_hex(to) _from = self.tron.address.to_hex(account) _token_id = self.tron.toHex(text=str(token_id)) if _to == _from: raise TronError('Cannot transfer TRX to the same account') # In case if "TRX" is specified, we redirect to another method. if is_string(token_id) and token_id.upper() == 'TRX': return self.send_transaction(_to, amount, _from) return self.tron.manager.request( '/wallet/transferasset', { 'to_address': _to, 'owner_address': _from, 'asset_name': _token_id, 'amount': amount })
def check_permissions(self, permissions, _type): if permissions is not None: if permissions['type'] != _type or \ not permissions['permission_name'] or \ not is_string(permissions['permission_name']) or \ not is_integer(permissions['threshold']) or \ permissions['threshold'] < 1 or not permissions['keys']: return False for key in permissions['key']: if not self.tron.isAddress(key['address']) or \ not is_integer(key['weight']) or \ key['weight'] > permissions['threshold'] or \ key['weight'] < 1 or _type == 2 and not permissions['operations']: return False return True
def __init__(self, tron, providers): """Create new manager tron instance Args: tron: The tron implementation providers: List of providers """ self.tron = tron self.providers = providers self.preferred_node = None for key, value in self.providers.items(): # This condition checks the nodes, # if the link to the node is not specified, # we insert the default value to avoid an error. if not providers[key]: self.providers[key] = HttpProvider(DEFAULT_NODES[key]) # If the type of the accepted provider is lower-case, # then we transform it to “HttpProvider”, if is_string(value): self.providers[key] = HttpProvider(value) self.providers[key].status_page = STATUS_PAGE[key]
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) precision = kwargs.setdefault('precision', 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( 'voteScore must be a positive integer greater than 0') if not is_integer(precision) or precision <= 0 or precision > 6: raise ValueError( 'precision must be a positive integer > 0 and <= 6') 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, 'precision': precision }) return response
def trigger_smart_contract(self, **kwargs): """Trigger Smart Contract Calls a function on a contract Args: **kwargs: Fill in the required parameters Examples: >>> tron = Tron() >>> tron.transaction_builder.trigger_smart_contract( >>> contract_address='413c8143e98b3e2fe1b1a8fb82b34557505a752390', >>> function_selector='set(uint256,uint256)', >>> fee_limit=30000, >>> call_value=0, >>> parameters=[ >>> {'type': 'int256', 'value': 1}, >>> {'type': 'int256', 'value': 1} ] ) Returns: TransactionExtention, TransactionExtention contains unsigned Transaction """ contract_address = kwargs.setdefault('contract_address', None) function_selector = kwargs.setdefault('function_selector', None) parameters = kwargs.setdefault('parameters', []) issuer_address = kwargs.setdefault('issuer_address', self.tron.default_address.hex) call_value = kwargs.setdefault('call_value', 0) fee_limit = kwargs.setdefault('fee_limit', 1000000000) token_value = kwargs.setdefault('token_value', 0) token_id = kwargs.setdefault('token_id', 0) if not is_integer(token_value) or token_value < 0: raise ValueError('Invalid options.tokenValue provided') if not is_integer(token_id) or token_id < 0: raise ValueError('Invalid options.tokenId provided') 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') function_selector = function_selector.replace('/\s*/g', '') 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 = '' data = { '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 } if token_value: data.call_token_value = int(token_value) if token_id: data.token_id = int(token_id) return self.tron.manager.request('/wallet/triggersmartcontract', data)
def is_hex_encoded_block_hash(value): if not is_string(value): return False return len(remove_0x_prefix(value)) == 64 and is_hex(value)
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 })