def is_hex_address(value: Any) -> bool: """Checks if the given string of text type is an address in hexadecimal encoded form.""" if len(value) != 42: return False elif not is_text(value): return False elif not is_hex(value): return False else: return is_address(hex_to_base58(value))
def to_hex(address): """Helper function that will convert a generic value to hex Args: address (str): address """ if is_hex(address): return address.lower().replace('0x', '41', 2) return base58.b58decode_check(address).hex().upper()
def from_hex(address): """Helper function that will convert a generic value from hex Args: address (str): address """ if not is_hex(address): return address return base58.b58encode_check(bytes.fromhex(address))
def sign(self, transaction: Any, use_tron: bool = True): """Sign the transaction, the api has the risk of leaking the private key, please make sure to call the api in a secure environment Warnings: Do not use this in any web / user-facing applications. This will expose the private key. Args: transaction (Any): transaction details use_tron (bool): is Tron header """ if is_string(transaction): if not is_hex(transaction): raise TronError('Expected hex message input') # Determine which header to attach to the message # before encrypting or decrypting header = TRX_MESSAGE_HEADER if use_tron else ETH_MESSAGE_HEADER header += str(len(transaction)) message_hash = self.tron.sha3(text=header + transaction) signed_message = Account.signHash( message_hash, private_key=self.tron.private_key) return signed_message if 'signature' in transaction: raise TronError('Transaction is already signed') address = self.tron.address.from_private_key( self.tron.private_key).hex.lower() owner_address = transaction['raw_data']['contract'][0]['parameter'][ 'value']['owner_address'] if address != owner_address: raise ValueError( 'Private key does not match address in transaction') # This option deals with signing of transactions, and writing to the array signed_tx = Account.signHash(message_hash=transaction['txID'], private_key=self.tron.private_key) transaction['signature'] = [signed_tx['signature'].hex()[2:]] return transaction
def get_block(self, block=None): """Get block details using HashString or blockNumber Args: block (int|str): Number or Hash Block """ if block is None: block = self.default_block if block == 'earliest': block = 0 if block == 'latest': return self.get_current_block() if is_hex(block): return self.get_block_by_hash(block) return self.get_block_by_number(int(block))
def sign(self, transaction: Any, use_tron: bool = True): """Sign the transaction, the api has the risk of leaking the private key, please make sure to call the api in a secure environment Args: transaction (Any): transaction details use_tron (bool): is Tron header """ if is_string(transaction): if not is_hex(transaction): raise TronError('Expected hex message input') # Determine which header to attach to the message # before encrypting or decrypting header = TRX_MESSAGE_HEADER if use_tron else ETH_MESSAGE_HEADER message_hash = self.tron.sha3(text=header + transaction) signed_message = EthAccount.signHash( message_hash, private_key=self.tron.private_key) return signed_message if 'signature' in transaction: raise TronError('Transaction is already signed') address = self.tron.address.from_private_key( self.tron.private_key).hex.lower() owner_address = transaction['raw_data']['contract'][0]['parameter'][ 'value']['owner_address'] if address != owner_address: raise ValueError( 'Private key does not match address in transaction') return self.tron.manager.request('/wallet/gettransactionsign', { 'transaction': transaction, 'privateKey': self.tron.private_key })
def verify_message(self, message, signed_message=None, address=None, use_tron: bool = True): """ Get the address of the account that signed the message with the given hash. You must specify exactly one of: vrs or signature Args: message (str): The message in the format "hex" signed_message (AttributeDict): Signature address (str): is Address use_tron (bool): is Tron header """ if address is None: address = self.tron.default_address.base58 if not is_hex(message): raise TronError('Expected hex message input') # Determine which header to attach to the message # before encrypting or decrypting header = TRX_MESSAGE_HEADER if use_tron else ETH_MESSAGE_HEADER message_hash = self.tron.sha3(text=header + message) recovered = Account.recoverHash(message_hash, signature=signed_message.signature) tron_address = '41' + recovered[2:] base58address = self.tron.address.from_hex(tron_address).decode() if base58address == address: return True raise ValueError('Signature does not match')
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 is_hex_encoded_block_hash(value): if not is_string(value): return False return len(remove_0x_prefix(value)) == 64 and is_hex(value)