def getAddressDetails(self): while not thread_stop_event.isSet(): publickey = 'GBCCC62LUXPDL7DLNQPYJWASA672CCJOLCJRBSIFXNIPRMQRRQ2HCWW6' target = 1000 address = Address(address=publickey) # testnet # address = Address(address=publickey, network='public') # livenet address.get() # Get the latest information from Horizon last_payment = address.payments(order='desc', limit=1) if 'transaction_successful' in last_payment['_embedded'][ 'records'][0]: success = bool(last_payment['_embedded']['records'][0] ['transaction_successful']) else: success = False if 'amount' in last_payment['_embedded']['records'][0] and success: amount = int( float(last_payment['_embedded']['records'][0]['amount'])) else: amount = '' if 'asset_code' in last_payment['_embedded']['records'][ 0] and success: asset_code = last_payment['_embedded']['records'][0][ 'asset_code'] elif 'asset_code' not in last_payment['_embedded']['records'][ 0] and success: asset_code = 'XLM' else: asset_code = '' balance = address.balances if 'balance' in balance[-1] and success: balance = int(float(balance[-1]['balance'])) else: balance = '' last_transaction = address.transactions(order='desc', limit=1) if 'memo' in last_transaction['_embedded']['records'][ 0] and success: memo = last_transaction['_embedded']['records'][0]['memo'] else: memo = '' socketio.emit('address_details', { 'publickey': publickey, 'target': target, 'balance': balance, 'memo': memo, 'amount': amount, 'asset_code': asset_code }, namespace='/test') sleep(self.delay)
def history(): c = Address(CONF['public_key'], network=CONF['network']) c.get() h = c.payments(limit=30, order='desc') for x in h[u'_embedded']['records']: if x['type'] == 'create_account': print(x['created_at'] + ' ' + x['type'] + ' start ' + x['starting_balance'] + '\n' + horiz_lp() + '/operations/' + x['id']) else: print(x['created_at'] + ' ' + x['type'] + ' ' + x['to'] + ' ' + x['from'] + ' ' + x['amount'] + '\n' + horiz_lp() + '/operations/' + x['id'])
# You may get a warning that the connection failed, but don't panic, # the program will always try to reconnect. # see: https://github.com/StellarCN/py-stellar-base/issues/152 from stellar_base.address import Address address = 'GAHK7EEG2WWHVKDNT4CEQFZGKF2LGDSW2IVM4S5DP42RBW3K6BTODB4A' horizon = 'https://horizon.stellar.org' cursor = 'now' # or load where you left off address = Address(address=address, horizon_uri=horizon) def payment_handler(response): print(response.data) payments = address.payments(sse=True, cursor=cursor) for payment in payments: payment_handler(payment)
# This script is for testing notification responses in console. from stellar_base.address import Address import config address = Address(address=config.address, horizon_uri=config.horizon) # Trade complete response - Need to add transaction info def payment_handler(response): print(response) # Check for new trade payments = address.payments(sse=True, cursor='now') for payment in payments: payment_handler(payments)
class Interface: """ Interface to handle all API calls to third-party account. """ def __init__(self, account): self.account = account if account.secret: self.builder = Builder(secret=account.secret, network=account.network) self.address = Address(address=account.account_id, network=account.network) def _get_new_receives(self): # Get all stored transactions for account transactions = ReceiveTransaction.filter(admin_account=self.account) # Set the cursor according to latest stored transaction: if not transactions: cursor = None else: cursor = int(transactions.latest().data['paging_token']) + 1 # Get new transactions from the stellar network: new_transactions = self._get_receives(cursor=cursor) return new_transactions def _get_receives(self, cursor=None): # If cursor was specified, get all transactions after the cursor: if cursor: transactions = self.address.payments(cursor=cursor)['_embedded']['records'] print(transactions) for i, tx in enumerate(transactions): if tx.get('to') != self.account.account_id: transactions.pop(i) # remove sends # else just get all the transactions: else: transactions = self.address.payments()['_embedded']['records'] for i, tx in enumerate(transactions): if tx.get('from') == self.account.account_id: transactions.pop(i) # remove sends return transactions def _process_receive(self, tx): # Get memo: details = requests.get(url=tx['_links']['transaction']['href']).json() memo = details.get('memo') print('memo: ' + str(memo)) if memo: account_id = memo + '*rehive.com' user_account = UserAccount.objects.get(account_id=account_id) user_email = user_account.user_id # for this implementation, user_id is the user's email amount = to_cents(Decimal(tx['amount']), 7) if tx['asset_type'] == 'native': currency = 'XLM' issuer = '' else: currency = tx['asset_code'] issuer_address = tx['asset_issuer'] issuer = Asset.objects.get(account_id=issuer_address, code=currency).issuer # Create Transaction: tx = ReceiveTransaction.objects.create(user_account=user_account, external_id=tx['hash'], recipient=user_email, amount=amount, currency=currency, issuer=issuer, status='Waiting', data=tx, metadata={'type': 'stellar'} ) # TODO: Move tx.upload_to_rehive() to a signal to auto-run after Transaction creation. tx.upload_to_rehive() return True @staticmethod def _is_valid_address(address: str) -> bool: # TODO: Replace with real address check. if len(address) == 56 and '*' not in address: return True else: return False # This function should always be included if transactions are received to admin account and not added via webhooks: def process_receives(self): # Get new receive transactions new_transactions = self._get_new_receives() # Add each transaction to Rehive and log in transaction table: for tx in new_transactions: self._process_receive(tx) # This function should always be included. def process_send(self, tx): if self._is_valid_address(tx.recipient): address = tx.recipient else: federation = get_federation_details(tx.recipient) if federation['memo_type'] == 'text': self.builder.add_text_memo(federation['memo']) elif federation['memo_type'] == 'id': self.builder.add_id_memo(federation['memo']) elif federation['memo_type'] == 'hash': self.builder.add_hash_memo(federation['memo']) else: raise NotImplementedAPIError('Invalid memo type specified.') address = federation['account_id'] # Create account or create payment: if tx.currency == 'XLM': try: address_obj = self.address address_obj.get() self.builder.append_payment_op(address, tx.amount, 'XLM') except APIException as exc: if exc.status_code == 404: self.builder.append_create_account_op(address, tx.amount) else: # Get issuer address details: issuer_address = get_issuer_address(tx.issuer, tx.currency) address_obj = self.address address_obj.get() self.builder.append_payment_op(address, tx.amount, tx.currency, issuer_address) try: self.builder.sign() self.builder.submit() except Exception as exc: print(exc.payload) def get_balance(self): address = self.address address.get() for balance in address.balances: if balance['asset_type'] == 'native': return to_cents(Decimal(balance['balance']), 7) def get_issuer_address(self, issuer, asset_code): if self._is_valid_address(issuer): address = issuer else: if '*' in issuer: address = get_federation_details(issuer)['account_id'] else: # assume it is an anchor domain address = address_from_domain(issuer, asset_code) return address def trust_issuer(self, asset_code, issuer): logger.info('Trusting issuer: %s %s' % (issuer, asset_code)) address = self.get_issuer_address(issuer, asset_code) self.builder.append_trust_op(address, asset_code) try: self.builder.sign() self.builder.submit() except Exception as exc: print(exc.payload) # Generate new crypto address/ account id @staticmethod def new_account_id(**kwargs): metadata = kwargs.get('metadata') account_id = metadata['username'] + '*' + getattr(settings, 'STELLAR_WALLET_DOMAIN') return account_id def get_account_details(self): address = self.account.account_id qr_code = create_qr_code_url('stellar:' + str(address)) return {'account_id': address, 'metadata': {'qr_code': qr_code}}
from stellar_base.address import Address publickey = 'GBCCC62LUXPDL7DLNQPYJWASA672CCJOLCJRBSIFXNIPRMQRRQ2HCWW6'#'GAU3DAERZWH4DC4XTUQ5IXYHJHZ67LQ5OCXU5GJJOADIPSJMGELBJAFW' address = Address(address=publickey) # See signature for additional args address.get() # Get the latest information from Horizon balance = address.balances print(address.balances) if 'balance' in balance[-1]: print('balance: {}'.format(int(float(balance[-1]['balance'])))) last_transaction = address.transactions(order='desc', limit=1) if 'memo' in last_transaction['_embedded']['records'][0]: print('memo: {}'.format(last_transaction['_embedded']['records'][0]['memo'])) last_payment = address.payments(order='desc', limit=1) if 'amount' in last_payment['_embedded']['records'][0]: print('amount: {}'.format(last_payment['_embedded']['records'][0]['amount'])) if 'asset_type' in last_payment['_embedded']['records'][0]: print('asset_type: {}'.format(last_payment['_embedded']['records'][0]['asset_type'])) if 'asset_code' in last_payment['_embedded']['records'][0]: print('asset_code: {}'.format(last_payment['_embedded']['records'][0]['asset_code'])) if 'transaction_successful' in last_payment['_embedded']['records'][0]: print('success: {}'.format(bool(last_payment['_embedded']['records'][0]['transaction_successful']))) if last_payment['_embedded']['records'][0]['from'] == publickey: print("Ignore") else: print("Valid")
class LumenautGazer: def __init__(self, public_key, webhook_url, data_dir="/var/lib/LumenautGazer", minimum_amount=0.1, dry_run=False): # On first run, we need to create the datadir if not os.path.exists(data_dir): os.makedirs(data_dir) if not public_key: raise ValueError("Please provide public_key.") self.public_key = public_key self.webhook_url = webhook_url self.minimum_amount = minimum_amount self.address = Address(address=self.public_key, network='public') self.last_cursor_filepath = os.path.join( data_dir, "{}{}".format(self.public_key, '_cursor')) self.dry_run = dry_run def _get_last_cursor(self): try: # Attempt to read the last cursor from the file with open(self.last_cursor_filepath, 'r') as input_: last_cursor = input_.read() try: return int(last_cursor) except ValueError: return None except FileNotFoundError: return None def poll(self): """ Query for all payments since last cursor. For each payment, notify and save last_cursor to datadir """ # Welcome message for the first time last_cursor = self._get_last_cursor() if not last_cursor: message = "Hi there! I'll let you know if there are transaction from/to {}.".format( self.public_key) self._notify(message) # Get last 10 payment from last cursor payment_data = self.address.payments( cursor=last_cursor)['_embedded']['records'] # No payments, do nothing if not payment_data: return last_notified_cursor = None for payment in payment_data: current_cursor = payment['paging_token'] # Discard other operations, only interested in payment currently if payment['type_i'] != 1: print('Not transaction, discarding {}'.format(current_cursor)) last_notified_cursor = current_cursor continue if float(payment['amount']) < self.minimum_amount: print('Amount too small, discarding {}'.format(current_cursor)) last_notified_cursor = current_cursor continue # Build message to notify transaction_url = "https://stellar.expert/explorer/tx/{hash}".format( hash=payment['transaction_hash']) if payment['to'] == self.public_key: message = "{amount} XLM Received from {source}. Details: {url}".format( amount=payment['amount'], source=payment['from'], url=transaction_url) else: message = "{amount} XLM sent to {destination}. Details: {url}".format( amount=payment['amount'], destination=payment['to'], url=transaction_url) # Try to notify, if we fail, bail out of the loop and persist last # Notified cursor if self._notify(message): last_notified_cursor = current_cursor else: break # Persist last notified cursor if last_notified_cursor: self._set_last_cursor(last_notified_cursor) def _notify(self, message): """ Notify whatever channel we need. Return True when notification success, False when failed """ if self.dry_run: print("Will send this message '{}' to {}".format( message, self.webhook_url)) return True else: try: response = requests.post(self.webhook_url, data=json.dumps({"text": message}), timeout=5) if response.status_code == requests.codes.ok: return True except Exception: # We don't care about any errors, simply bail out and retry later print("Problem sending notification. Bailing out!") pass return False def _set_last_cursor(self, cursor): with open(self.last_cursor_filepath, 'w') as output_: output_.write(cursor)