def get_transfers(full_history, print_history=True): account_history_executing = True api = Iota(iota_node, seed) address_count = len(address_data) all_txn_hashes = [] saved_txn_hashes = [] new_txn_hashes = [] i = 0 while i < address_count: address = address_data[i]["address"] address_as_bytes = [bytes(address)] raw_transfers = api.find_transactions(addresses=address_as_bytes) transactions_to_check = raw_transfers["hashes"] for txn_hash in transactions_to_check: txn_hash = str(txn_hash) all_txn_hashes.append(txn_hash) i += 1 for txn_hash in transfers_data: txn_hash = str(txn_hash['transaction_hash']) saved_txn_hashes.append(txn_hash) for txn_hash in all_txn_hashes: if txn_hash not in saved_txn_hashes: new_txn_hashes.append(txn_hash) if len(new_txn_hashes) > 0: print("Retreaving and saving transfer data from " + str(len(new_txn_hashes)) + " transaction(s)!\n" "Please wait...\n") for txn_hash in new_txn_hashes: txn_hash_as_bytes = bytes(txn_hash) li_result = api.get_latest_inclusion([ txn_hash_as_bytes ]) # Needs to be integrated into new transactions as well is_confirmed = li_result['states'][txn_hash] print(li_result) gt_result = api.get_trytes([txn_hash_as_bytes]) trytes = str(gt_result['trytes'][0]) txn = Transaction.from_tryte_string(trytes) timestamp = str(txn.timestamp) tag = str(txn.tag) address = str(txn.address) message = "some message" # Placeholder untill message decoding is added value = str(txn.value) bundle = str(txn.bundle_hash) write_transfers_data(txn_hash, is_confirmed, timestamp, tag, address, message, value, bundle) if full_history: print_transaction_history(full_history, print_history) elif not full_history: print_transaction_history(full_history, print_history)
def test_wireup(self): """ Verify that the command is wired up correctly. The API method indeed calls the appropiate command. """ with patch( 'iota.commands.extended.get_latest_inclusion.GetLatestInclusionCommand.__call__', MagicMock(return_value='You found me!')) as mocked_command: api = Iota(self.adapter) # Don't need to call with proper args here. response = api.get_latest_inclusion('hashes') self.assertTrue(mocked_command.called) self.assertEqual(response, 'You found me!')
class MyIOTA: def __init__(self, node, seed): self.node = node self.seed = seed self.api = False self._update = False self.transfers = [] self._debug = False self.wallet = self.get_filename() self.addr_dict = {} self.min_weight_magnitude = 14 self.api = Iota(self.node, self.seed) self.USED = True self.NOT_USED = False def Address(self, addr_string): return Address(addr_string) def get_addr_dict(self): return self.addr_dict def set_addr_dict(self, addr, value, used): self.addr_dict[addr] = (value, used) def s_addr(self, addr, n=3): s_addr = str(addr) l = len(s_addr) return s_addr[:n] + '...' + s_addr[l - n:] def get_filename(self): h = hashlib.sha256() h.update(self.seed) filename = h.hexdigest()[:20] + '.txt' return filename def init_wallet(self): filename = self.wallet # file exists if os.path.isfile(filename): filefd = open(filename, 'r+') self.debug( 'Wallet file {0} exists. Opening it...'.format(filename)) for line in filefd: line = line.rstrip('\n') addr, index, value, used = line.split(',') self.debug('reading from file: {0},{1},{2}'.format( self.s_addr(addr, 3), value, used)) used = used == 'True' addr = Address(addr, key_index=int(index), security_level=2) self.addr_dict[addr] = (int(index), int(value), used) filefd.close() else: filefd = open(filename, 'w') self.debug('Wallet file {0} doesnt exist. Creating it...'.format( filename)) filefd.close() def is_empty_wallet(self): return len(self.addr_dict) == 0 def get_fund_inputs(self, inputs): total_fund = 0 for addr in inputs: index, value, used = self.addr_dict[addr] # TODO: abs. is this right? total_fund += abs(value) return total_fund def write_updates(self): filefd = open(self.wallet, 'w') self.debug('Writing (updating) wallet...') for addr in self.addr_dict: v = self.addr_dict[addr] line = 'Writing: {0},{1},{2},{3}\n'.format(self.s_addr(addr), v[0], v[1], v[2]) self.debug(line) filefd.write('{0},{1},{2},{3}\n'.format(addr, v[0], v[1], v[2])) filefd.close() def update_wallet(self, input_fund, inputs, change_addr): copy_dict = self.addr_dict.copy() for addr in inputs: v = self.addr_dict[addr] #self.debug('Spending {0} from input {1}'.format(self.s_addr(addr), v)) # Negative fund and used address new_value = (v[0], -v[1], not v[2]) self.debug('Updating input address {0} to: {1}'.format( self.s_addr(addr), new_value)) self.addr_dict[addr] = new_value change_fund = self.get_fund_inputs(inputs) - input_fund v = self.addr_dict[change_addr] change_value = (v[0], change_fund, self.NOT_USED) self.debug('Updating change address {0} to: {1}'.format( self.s_addr(change_addr), change_value)) self.addr_dict[change_addr] = change_value self.write_updates() def enable_debug(self): self._debug = True def debug(self, msg): if self._debug: print '[+] Debug: ', msg def get_node_info(self): return self.api.get_node_info() def make_addr_list(self, start_index, n): self.iota_assert(start_index >= 0 and n > 0, 'must be positive numbers. N should be at least 1.') result = self.api.get_new_addresses(index=start_index, count=n) addresses = result['addresses'] for i in range(n): addr = addresses[i] value = self.get_addr_balance(addr) # TODO: Why always False self.addr_dict[addr] = (i, value, False) self.write_updates() def get_addr_balance(self, addr): # TODO: addr is a list with just one element result = self.api.get_balances([addr]) balance = result['balances'] return (balance[0]) def prepare_transfer(self, transfer_value, dest_addr, tag='DEFAULT', msg='DEFAULT'): # TODO: verify address (checksum) # TODO: use mi, gi, etc msg = TryteString.from_string(msg) txn = ProposedTransaction( address=Address(dest_addr), message=msg, tag=Tag(tag), value=transfer_value, ) return txn def find_transactions(self): addr_list = [] for e in self.addr_dict.items(): addr = e[0] addr_list.append(addr) return self.api.findTransactions(addresses=addr_list)['hashes'] def get_bundle(self, trans): return self.api.getBundles(transaction=trans) def get_latest_inclusion(self, addrl): return self.api.get_latest_inclusion(hashes=addrl) def get_total_fund(self): total_fund = 0 for addr in self.addr_dict.items(): # key and value from dict k, v = addr index, value, used = v #if not used: total_fund += value return total_fund def get_number_of_address(self): return len(self.addr_dict) def is_all_addr_used(self): for addr in self.addr_dict: for e in self.addr_dict.items(): addr, v = e index, value, used = v if used == False: return True def get_more_addr(self, n=10): start_index = self.get_number_of_address() self.debug('Getting more addresses...please wait...') self.make_addr_list(start_index, n) def send_transfer(self, input_fund, inputs, outputs, change_addr, savetofile=True): # TODO: How to send MANY transactions. self.debug('Sending {0} transactions, please wait...'.format( len(outputs))) self.api.send_transfer(inputs=inputs, transfers=outputs, depth=7, change_address=change_addr, min_weight_magnitude=self.min_weight_magnitude) self.debug('Sent.') if self.is_all_addr_used(): # We do an update to wallet file here. self.get_more_addr(n=10) if savetofile: self.update_wallet(input_fund, inputs, change_addr) def get_bundles(self, hasht): return self.api.get_bundles(hasht) def get_trytes(self, hashl): return self.api.get_trytes(hashl)['trytes'][0] def get_transaction_from_trytes(self, trytes): txn = Transaction.from_tryte_string(trytes) return txn def get_transaction_fields(self, txn): #confirmed = str(txn.is_confirmed) timestamp = str(txn.timestamp) address = str(txn.address) value = str(txn.value) message = str(txn.signature_message_fragment) #message = str(txn.message) tag = str(txn.tag) return (timestamp, address, value, tag, message) def get_info_transactions(self, transactions_hashes): txn_tuples = [] for h in transactions_hashes: trytes = self.get_trytes([h]) txn = self.get_transaction_from_trytes(trytes) # Get confirmed flag li_result = self.get_latest_inclusion([bytes(h)]) confirmed_t = li_result['states'][h] (_, addr_t, value_t, tag_t, msg_t) = self.get_transaction_fields(txn) txn_tuples.append((confirmed_t, addr_t, value_t, tag_t, msg_t)) return txn_tuples def get_any_valid_addr(self): #TODO: verify #return self.addr_dict.keys()[0] for e in self.addr_dict.items(): addr, v = e index, value, used = v if not used: return addr return None def get_inputs(self, fund): # TODO: Zero fund fund_sum = 0 addr_list = [] change_addr = None # Zero fund transactions. We return any addr and any change_addr if fund == 0: # TODO: What if it conflicts with one another? addr_list.append(self.get_any_valid_addr()) change_addr = self.get_any_valid_addr() return (addr_list, change_addr) for e in self.addr_dict.items(): addr, v = e index, value, used = v if fund_sum < fund: #if value > 0 and not used: if value > 0 and used == self.NOT_USED: fund_sum += value self.debug( 'Found request: {0}. Found address {1} with fund {2}.'. format(fund, self.s_addr(addr), value)) addr_list.append(addr) for e in self.addr_dict.items(): addr, v = e index, value, used = v if used == self.NOT_USED and addr not in addr_list: change_addr = addr self.debug('Using {0} as change addr.'.format( self.s_addr(addr))) break return (addr_list, change_addr) #else: # # TODO # self.iota_assert(True, 'No change addr available.') def iota_assert(self, condition, msg): if not condition: print 'Error: ', msg sys.exit(-1)
class Wallet: """docstring for Wallet""" def __init__(self, uri: str, seed: Optional[str] = None) -> None: self._iota_api = Iota(uri, seed) self._account: _Account @property def account(self) -> _Account: try: return self._account except AttributeError: # We get an attibute error if we check this property before ever # calling refresh_account. self.refresh_account() return self._account @property def addresses(self) -> List[Address]: return self.account.addresses @property def balance(self) -> int: return self.account.balance @property def bundles(self) -> Dict[str, Iterable[Bundle]]: return { 'confirmed': self.account.confirmed_bundles, 'unconfirmed': self.account.unconfirmed_bundles, 'duplicate': self.account.duplicate_bundles, } def _is_above_max_depth(self, transaction: Transaction) -> bool: current_millis = time.time() * 1000 max_age = 11 * 60 * 1000 # 11 minutes diff = current_millis - cast(float, transaction.attachment_timestamp) return (0 < diff < max_age) def _is_promotable(self, bundle: Bundle) -> bool: return (self._is_above_max_depth(bundle.tail_transaction) and self._iota_api.helpers.is_promotable( bundle.tail_transaction.hash)) def _promote(self, bundle: Bundle) -> Bundle: tail_hash = bundle.tail_transaction.hash response = self._iota_api.get_latest_inclusion([tail_hash]) if response['states'][tail_hash]: raise BundleAlreadyPromoted() response = self._iota_api.promote_transaction(transaction=tail_hash, depth=DEPTH) return response['bundle'] def _reattach(self, bundle: Bundle) -> Bundle: response = self._iota_api.replay_bundle( bundle.tail_transaction.hash, DEPTH, ) return Bundle.from_tryte_strings(response['trytes']) def create_new_address(self) -> Address: response = self._iota_api.get_new_addresses(count=None) address = response['addresses'][0] # Attach the address self._iota_api.send_transfer( depth=DEPTH, transfers=[ProposedTransaction(address, value=0)], ) return address def refresh_account(self) -> None: response = self._iota_api.get_account_data(inclusion_states=True) addresses = response['addresses'] balance = response['balance'] bundles = response['bundles'] self._account = _Account(addresses, balance, bundles) def retry_unconfirmed_bundles(self, *bundles: Bundle) -> None: if len(bundles) == 0: bundles = tuple(self.bundles['unconfirmed']) for bundle in bundles: print(f'Retrying bundle: {bundle.hash}') if not self._is_promotable(bundle): bundle = self._reattach(bundle) while True: time.sleep(2) if self._is_promotable(bundle): break for attempt in range(5): try: promote_bundle = self._promote(bundle) except BundleAlreadyPromoted: break else: print( f'Promotion attempt ({attempt}): Bundle {promote_bundle.hash}' ) def send(self, address: str, value: int) -> None: print(f'Sending {value} iota to {address}...') response = self._iota_api.send_transfer( depth=DEPTH, transfers=[ProposedTransaction(Address(address), value=value)]) bundle = response['bundle'] print(f'Iota sent! Bundle hash: {bundle.hash}')
def get_transfers(self, full_history, print_history=False): """ Gets all associated transactions from the saved addresses and saves the transaction data in the account file :param full_history: :param print_history: :return: """ self._account_history_executing = True api = Iota(self.iota_node, self._seed) address_count = len(self._data['account_data'][0]['address_data']) my_all_txn_hashes = {} all_txn_hashes = [] saved_txn_hashes = [] new_txn_hashes = [] i = 0 while i < address_count: address = self._data['account_data'][0]['address_data'][i][ "address"] address_as_bytes = [address] raw_transfers = api.find_transactions(addresses=address_as_bytes) transactions_to_check = raw_transfers["hashes"] for txn_hash in transactions_to_check: str_txn_hash = str(txn_hash) all_txn_hashes.append(str_txn_hash) my_all_txn_hashes[str_txn_hash] = txn_hash i += 1 for txn_hash in self._data['account_data'][0]['transfers_data']: txn_hash = str(txn_hash['transaction_hash']) saved_txn_hashes.append(txn_hash) for th in my_all_txn_hashes: if th not in saved_txn_hashes: new_txn_hashes.append(my_all_txn_hashes[th]) if len(new_txn_hashes) > 0: self._logger.info("Retrieving and saving transfer data from " + str(len(new_txn_hashes)) + " transaction(s)! Please wait...") for txn_hash in new_txn_hashes: li_result = api.get_latest_inclusion([ txn_hash ]) # Needs to be integrated into new transactions as well is_confirmed = li_result['states'][txn_hash] gt_result = api.get_trytes([txn_hash]) trytes = str(gt_result['trytes'][0]) txn = Transaction.from_tryte_string(trytes) timestamp = str(txn.timestamp) tag = str(txn.tag) address = str(txn.address) message = "some message" # Placeholder untill message decoding is added value = str(txn.value) bundle = str(txn.bundle_hash) self._write_transfers_data(str(txn_hash), is_confirmed, timestamp, tag, address, message, value, bundle) self.on_new_transaction_received(txn, is_confirmed) if print_history: if full_history: self.print_full_account_info() elif not full_history: self.print_standard_account_info() self._account_history_executing = False