def sign(self, transaction: Any, use_tron: bool = True): """Safe method for signing your transaction Warnings: method: online_sign() - Use only in extreme cases. 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.sign_hash(message_hash, 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.sign_hash(transaction['txID'], self.tron.private_key) transaction['signature'] = [signed_tx['signature'].hex()[2:]] return transaction
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 header += str(len(message)) message_hash = self.tron.keccak(text=header + message) recovered = Account.recover_hash(self.tron.toHex(message_hash), 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 to_hex(address): """Helper function that will convert a generic value to hex""" 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""" if not is_hex(address): return address return base58.b58encode_check(bytes.fromhex(address))
def recover_hash(message_hash, signature): if not is_hex(message_hash): raise ValueError('Invalid message_hash provided') return ETHAccount.recoverHash(message_hash, signature=signature)
def sign_hash(message_hash, private_key): if not is_hex(message_hash): raise ValueError('Invalid message_hash provided') return ETHAccount.signHash(message_hash, private_key)
def sign(self, transaction: Any, private_key=None, use_tron: bool = True, multisig: bool = False, is_message_hex=False): """Safe method for signing your transaction Warnings: method: online_sign() - Use only in extreme cases. Args: transaction (Any): transaction details use_tron (bool): is Tron header multisig (bool): multi sign """ 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)) if is_message_hex: from eth_hash.auto import keccak as keccak_256 message_hash = keccak_256( header.encode('utf-8') + bytes.fromhex(transaction)) else: message_hash = self.tron.keccak(text=header + transaction) signed_message = Account.sign_hash( self.tron.toHex(message_hash), private_key or self.tron.private_key) return signed_message if not multisig and 'signature' in transaction: raise TronError('Transaction is already signed') try: if not multisig: address = self.tron.address.from_private_key( private_key or 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.sign_hash(transaction['txID'], private_key or self.tron.private_key) signature = signed_tx['signature'].hex()[2:] # support multi sign if 'signature' in transaction and is_list( transaction['signature']): if not transaction['signature'].index(signature): transaction['signature'].append(signature) else: transaction['signature'] = [signature] return transaction except ValueError as err: raise InvalidTronError(err)
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)