def detail(request, str_addr): hz = Horizon() r = hz.account(str_addr)['balances'] print(r) x = {'r': r} #return HttpResponse("You're looking at question %s." % r) return render(request, 'stellar/accountdetails.html', x)
def get_sequence(address): h = Horizon() account = h.account(address) try: return account['sequence'] except: return False
def get_ledger_data(): # Create Horizon object ledger_data = Horizon(horizon_uri='https://horizon.stellar.org') # Start streaming from ledgers endpoint ledger_data = ledger_data.ledgers(cursor='now', order='asc', sse=True) # Handle responses for ledger in ledger_data: data_handler(ledger)
def accountdr(request, account_addr): hz = Horizon() if account_addr is None: address_addr = 'GDVRS4JT7QUXBYOZWDAJEQUBJC5L74Q5ASDYK5HROOGJHNBUVKB6CNGW' r = hz.account(address_addr)['balances'] print(r) x = {'r': r} return render(request, 'stellar/accountdetails.html', x)
def transactions(request): a = Accounts.objects.filter(user_name=request.user) address = a[0].address # = 'GDVRS4JT7QUXBYOZWDAJEQUBJC5L74Q5ASDYK5HROOGJHNBUVKB6CNGW' hz = Horizon() r = hz.account_payments(address) x = r['_embedded']['records'] r = {'r': x,'address': address} print(r) return render(request, 'stellar/transactions.html', r)
def get_balances(address): hz = Horizon() if address is None: anna1 = {'address': u'GDVRS4JT7QUXBYOZWDAJEQUBJC5L74Q5ASDYK5HROOGJHNBUVKB6CNGW', 'seed': u'SDIXGWLFZYV2DJYKJBUBSAC5HP33TGTQ5RKJSRFAQTMTBWUKCE3ATHRJ'} address = anna1['address'] print(address) r = hz.account(address)['balances'] return r
def check_degree(): if request.method == 'GET': return render_template('index.html', js_folder=url_for('static', filename='js'), img_folder=url_for('static', filename='img'), css_folder=url_for('static', filename='css'), verif=1) horizon = Horizon() try: # In this part we try to get the hash of the transaction in order to fetch it from horizon. The hash is easier to get from text, # that's why it's the first test. if 'txhash' in request.form and request.form.get('txhash'): tx = horizon.transaction(request.form.get('txhash')) elif 'txqr' in request.files: # If a qrcode is submitted, we have to save it to decode it, which causes security issues. qr = request.files.get('txqr') # if user does not select file, browser also # submit an empty part without filename if qr.filename == '': raise Exception("Vous devez spécifier au moins un hash OU un qrcode") else: if app.allowed_filename(qr.filename): fname = secure_filename(qr.filename) fpath = os.path.join(os.getcwd(), 'static', fname) qr.save(fpath) data = qreader.read(fpath) os.remove(fpath) # We don't need it anymore tx = horizon.transaction(data) else: raise Exception("Merci de ne passer que des images générées par ce site") else: raise Exception("Vous devez spécifier au moins un hash OU un qrcode") # Hashing infos from the form to check the hash with the one in the transaction's memo name = request.form.get('name') birthdate = request.form.get('birthdate') year = request.form.get('year') h = hash128((name+birthdate+year).encode()) if h == tx.get('memo'): return render_template('index.html', js_folder=url_for('static', filename='js'), img_folder=url_for('static', filename='img'), css_folder=url_for('static', filename='css'), verif=1, verif_passed=1, id=tx.get('source_account'), name=name, birthdate=birthdate, year=year) else: return render_template('index.html', js_folder=url_for('static', filename='js'), img_folder=url_for('static', filename='img'), css_folder=url_for('static', filename='css'), verif=1, veriferror="Les informations saisies ne correspondent pas avec l'exemplaire du diplôme décerné") except Exception as e: return render_template('index.html', js_folder=url_for('static', filename='js'), img_folder=url_for('static', filename='img'), css_folder=url_for('static', filename='css'), verif=1, veriferror=e)
def main_loop(server): horizon = Horizon(server) operations = horizon.operations() global current_minute try: for resp in operations['_embedded']['records']: cm = resp['created_at'][:-4] log.info('minute change %s => %s' % (current_minute, cm)) if cm != current_minute: log.info('minute change %s => %s' % (current_minute, cm)) current_minute = cm global current_data global current_payment_detail global current_large_native_payment_detail op_type = resp['type'] current_data['nb_operation'] += 1 current_data['nb_operation_%s' % op_type] += 1 if op_type == 'payment': current_data['total_amount_payment'] += float(resp['amount']) if resp['asset_type'] == 'native': asset = 'native' v = float(resp['amount']) if v >= 10000: from_addr = resp['from'] to_addr = resp['to'] current_large_native_payment_detail[from_addr][ to_addr] += v else: asset = resp['asset_code'] current_payment_detail[asset]['nb'] += 1 current_payment_detail[asset]['sum'] += float(resp['amount']) except requests.exceptions.HTTPError as e: log.info(str(e)) lolog.infoo('http exception, restarting') return
def __init__(self, config): self.seed = os.environ.get('STELLAR_SEED') or config.get('stellar_seed') self.keypair = Keypair.from_seed(self.seed) self.address = self.keypair.address().decode() self.selling_asset = Asset(config['base_asset']['code'], config['base_asset']['issuer']) self.buying_asset = Asset(config['counter_asset']['code'], config['counter_asset']['issuer']) self.buying_amount = config['buying_amount'] self.buying_rate = config['buying_rate'] self.selling_amount = config['selling_amount'] self.selling_rate = config['selling_rate'] self.horizon_url = config['horizon'] self.horizon = Horizon(config['horizon']) self.network = 'public'
def get_horizon_client(self): if self.horizon_client: return self.horizon_client network_passphrase = self.network.network_id() if network_passphrase == NETWORKS['PUBLIC']: horizon_client = Horizon(urls['PUBLIC']) else: horizon_client = Horizon(urls['TESTNET']) self.horizon_client = horizon_client return self.horizon_client
def test_submit(setup, helpers): kp = Keypair.random() address = kp.address().decode() seed = kp.seed() helpers.fund_account(setup, address) horizon = Horizon(setup.horizon_endpoint_uri) envelope_xdr = make_envelope( setup.network, horizon, address, seed, Payment(destination=address, asset=Asset.native(), amount="0.0001618")) response = horizon.submit(envelope_xdr) assert 'hash' in response
def test_network_and_horizon(self, setup, test_data): builder = Builder(secret=test_data.cold_secret, sequence=100, network='MOE') assert builder.network == 'MOE' assert builder.horizon.horizon_uri == horizon_testnet().horizon_uri builder = Builder(secret=test_data.cold_secret, sequence=100, network='testnet') assert builder.network == 'TESTNET' assert builder.horizon.horizon_uri == horizon_testnet().horizon_uri builder = Builder(secret=test_data.cold_secret, sequence=100, network='public') assert builder.network == 'PUBLIC' assert builder.horizon.horizon_uri == horizon_livenet().horizon_uri builder = Builder(secret=test_data.cold_secret, sequence=100, network='public', horizon_uri=setup.horizon_endpoint_uri) assert builder.network == 'PUBLIC' assert builder.horizon.horizon_uri == Horizon( horizon_uri=setup.horizon_endpoint_uri).horizon_uri
def check_trustlines(): transactions = Transaction.objects.filter( status=Transaction.STATUS.pending_trust) for transaction in transactions: account = Horizon().account(transaction.stellar_account) try: balances = account["balances"] except KeyError: return for balance in balances: try: asset_code = balance["asset_code"] except KeyError: continue if asset_code == transaction.asset.name: create_stellar_deposit(transaction.id)
def check_trustlines(): """ Create Stellar transaction for deposit transactions marked as pending trust, if a trustline has been created. """ transactions = Transaction.objects.filter( status=Transaction.STATUS.pending_trust) for transaction in transactions: account = Horizon(horizon_uri=settings.HORIZON_URI).account( transaction.stellar_account) try: balances = account["balances"] except KeyError: return for balance in balances: try: asset_code = balance["asset_code"] except KeyError: continue if asset_code == transaction.asset.name: create_stellar_deposit(transaction.id)
class MarketMaker(object): def __init__(self, config): self.seed = os.environ.get('STELLAR_SEED') or config.get('stellar_seed') self.keypair = Keypair.from_seed(self.seed) self.address = self.keypair.address().decode() self.selling_asset = Asset(config['base_asset']['code'], config['base_asset']['issuer']) self.buying_asset = Asset(config['counter_asset']['code'], config['counter_asset']['issuer']) self.buying_amount = config['buying_amount'] self.buying_rate = config['buying_rate'] self.selling_amount = config['selling_amount'] self.selling_rate = config['selling_rate'] self.horizon_url = config['horizon'] self.horizon = Horizon(config['horizon']) self.network = 'public' def get_price(self): # 获取当前市场的价格,这里获取的是买一与卖一价,视情况改进,比如考虑市场深度? params = { "selling_asset_type": self.selling_asset.type, "selling_asset_code": self.selling_asset.code, "selling_asset_issuer": self.selling_asset.issuer, "buying_asset_type": self.buying_asset.type, "buying_asset_code": self.buying_asset.code, "buying_asset_issuer": self.buying_asset.issuer } data = self.horizon.order_book(params=params) # {'bid': '1.5310000', 'ask': '1.6000000'} 买一价与卖一价 return {'bid': data['bids'][0]['price'], 'ask': data['asks'][0]['price']} def get_account_data(self): # 获取账户信息 account = Address(address=self.address, network=self.network, horizon=self.horizon_url) account.get() return account def get_balance(self): # 获取当前交易对的余额信息 handled_balance = {} balances_data = self.get_account_data().balances for balance in balances_data: if balance['asset_type'] == 'native': handled_balance['XLM'] = balance['balance'] elif (balance['asset_code'] == self.selling_asset.code and balance['asset_issuer'] == self.selling_asset.issuer) or \ (balance['asset_code'] == self.buying_asset.code and balance['asset_issuer'] == self.buying_asset.issuer): handled_balance[balance['asset_code']] = balance['balance'] return handled_balance def handle_offers_data(self): # 对当前交易对的挂单信息进行处理,使其易于理解与使用 handled_offers_data = [] offers_data = self.get_account_data().offers()['_embedded']['records'] for data in offers_data: if ((data['selling']['asset_type'] == 'native' and self.selling_asset.type == 'native') or data['selling'][ 'asset_code'] == self.selling_asset.code and data['selling'][ 'asset_issuer'] == self.selling_asset.issuer) and ( (data['buying']['asset_type'] == 'native' and self.buying_asset.type == 'native') or data['buying'][ 'asset_code'] == self.buying_asset.code and data['buying']['asset_issuer'] == self.buying_asset.issuer): handled_offer = { 'id': data['id'], 'amount': data['amount'], 'price': data['price'], 'type': 'selling' } if ((data['buying']['asset_type'] == 'native' and self.selling_asset.type == 'native') or data['buying'][ 'asset_code'] == self.selling_asset.code and data['buying'][ 'asset_issuer'] == self.selling_asset.issuer) and ( (data['selling']['asset_type'] == 'native' and self.buying_asset.type == 'native') or data['selling']['asset_code'] == self.buying_asset.code and data['selling'][ 'asset_issuer'] == self.buying_asset.issuer): real_price = data['price_r']['d'] / data['price_r']['n'] format_price = '{:0,.7f}'.format(real_price) format_amount = '{:0,.7f}'.format( float(data['amount']) / real_price) handled_offer = { 'id': data['id'], 'amount': format_amount, 'price': format_price, 'type': 'buying' } handled_offers_data.append(handled_offer) return handled_offers_data def create_offers(self): # 创建挂单。这里是两个订单 # 买入价格 = 买一价 * (1 - buying_rate) # 卖出价格 = 卖一价 * (1 + selling_rate) market_price = self.get_price() builder = Builder(secret=self.seed, network=self.network, horizon=self.horizon_url) # 卖出 base_asset selling_price = round(float(market_price['ask']) * (1 + self.selling_rate), 7) builder.append_manage_offer_op(selling_code=self.selling_asset.code, selling_issuer=self.selling_asset.issuer, buying_code=self.buying_asset.code, buying_issuer=self.buying_asset.issuer, amount=self.selling_amount, price=selling_price) # 买入 base_asset buying_tmp_price = float(market_price['bid']) * (1 - self.buying_rate) buying_price = round(1 / buying_tmp_price, 7) buying_amount = round(self.buying_amount * buying_tmp_price, 7) builder.append_manage_offer_op(selling_code=self.buying_asset.code, selling_issuer=self.buying_asset.issuer, buying_code=self.selling_asset.code, buying_issuer=self.selling_asset.issuer, amount=buying_amount, price=buying_price) builder.sign() builder.submit() def cancel_all_offers(self): # 取消当前交易对的所有委单 offers = self.handle_offers_data() builder = Builder(secret=self.seed, network=self.network, horizon=self.horizon_url) for offer in offers: builder.append_manage_offer_op(selling_code=self.selling_asset.code, selling_issuer=self.selling_asset.issuer, buying_code=self.buying_asset.code, buying_issuer=self.buying_asset.issuer, amount='0', price='1', offer_id=offer['id']) builder.sign() builder.submit() def print_offer(self): # 显示当前委单 offers = self.handle_offers_data() for offer in offers: print("{type} {amount} {base_asset}, {price} {counter_asset}/{base_asset}".format( base_asset=self.selling_asset.code, counter_asset=self.buying_asset.code, **offer)) def start(self): print("Your address: " + self.address) print(self.get_balance()) self.cancel_all_offers() # 挂两个单,只有在两个委单都成交后才会重新挂单,视情况重写,目前测试用的是这样的,毕竟这样风险小。 while True: try: offers = self.handle_offers_data() if len(offers) != 0: time.sleep(3) else: self.create_offers() print("New offers created") self.print_offer() except Exception as e: print(e)
# encoding: utf-8 import requests import json from stellar_base.keypair import Keypair from stellar_base.memo import * from stellar_base.operation import * from stellar_base.builder import HORIZON_TEST from stellar_base.horizon import Horizon horizon = Horizon() class TestMethods: def __init__(self): kp = Keypair.random() self.fee = 100 self.address = kp.address().decode('ascii') self.seed = kp.seed().decode('ascii') or None fund(self.address) def make_envelope(self, *args, **kwargs): from stellar_base.transaction import Transaction from stellar_base.keypair import Keypair from stellar_base.transaction_envelope import TransactionEnvelope as Te opts = { 'sequence': horizon.account(self.address)['sequence'], 'fee': self.fee * len(args) } for opt, value in kwargs.items(): opts[opt] = value
def __init__(self, rpc_uri, timeout): self.client = Horizon(horizon=rpc_uri, timeout=timeout) # 测试节点 self.rpc_uri = rpc_uri
class XlmOP: def __init__(self, rpc_uri, timeout): self.client = Horizon(horizon=rpc_uri, timeout=timeout) # 测试节点 self.rpc_uri = rpc_uri # self.client = Horizon(horizon=horizon_livenet()) # 正式链 def generate_pri_keys(self): """ 生成随机公钥私钥 """ # sm = StellarMnemonic() # secret_phrase = sm.generate() # kp = Keypair.deterministic(secret_phrase) kp = Keypair.random() publickey = kp.address().decode() seed = kp.seed().decode() return seed, publickey def create_account(self, old_account_seed, new_account_address, amount, memo): """ 用已有账户创建新账户 """ horizon = self.client account_seed = old_account_seed old_account_keypair = Keypair.from_seed(account_seed) account_addr = new_account_address start_amount = amount # Your new account minimum balance (in XLM) to transfer over # create the CreateAccount operation opts = {'destination': account_addr, 'starting_balance': start_amount} op = CreateAccount(opts) # create a memo txt_memo = TextMemo(memo) # Get the current sequence of the source account by contacting Horizon. You # should also check the response for errors! try: sequence = horizon.account( old_account_keypair.address().decode()).get('sequence') except Exception as e: logger.exception(e) # Create a transaction with our single create account operation, with the # default fee of 100 stroops as of this writing (0.00001 XLM) trans_ops = { 'sequence': sequence, 'memo': txt_memo, 'operations': [op] } tx = Transaction(source=old_account_keypair.address().decode(), opts=trans_ops) env_opts = {'network_id': 'TESTNET'} envelope = TransactionEnvelope(tx=tx, opts=env_opts) # Sign the transaction envelope with the source keypair envelope.sign(old_account_keypair) # Submit the transaction to Horizon te_xdr = envelope.xdr() response = horizon.submit(te_xdr) return response def get_balance(self, publickey): """ 获取余额 """ res_obj = self.client.account(publickey) pprint(res_obj) # res = json.dumps(res_obj) balance = res_obj.get('balances', '')[0].get('balance', '') return balance def get_account_info(self, address): """ 获取账户信息 """ account_info = self.client.account(address) res = json.dumps(account_info) return res def create_transaction(self, from_address, to_address, amount, memo): """ 创建一笔交易 :param from_address: 发起账户的私钥 :param to_address: 目的账户的公钥 :return: response """ builder = Builder(secret=from_address, horizon_uri=self.rpc_uri) builder_memo = builder.add_text_memo(memo) builder_memo.append_payment_op(destination=to_address, amount=amount, asset_code='XLM') builder.sign() response = builder.submit() return response def get_transactions(self, publickey, cursor='now'): """ 获取交易列表 """ assert publickey and isinstance(publickey, str) params = {'order': 'desc', 'limit': '200', 'cursor': cursor} trras_res = self.client.account_transactions(publickey, params=params) pprint(trras_res) return trras_res.get('_embedded').get('records') def get_trans_info(self, txid): """ 获取交易信息 """ trans_res = self.client.transaction(txid) return trans_res def get_ledgers(self, cursor='now'): """ 获取当前区块信息 """ param = {'order': 'desc', 'limit': '200', 'cursor': cursor} res = self.client.ledgers(**param) return res['_embedded']['records'] def get_account_payments(self, address, cursor='now'): param = { 'order': 'desc', 'limit': '200', 'cursor': cursor, 'address': address } res = self.client.account_payments(**param) return res def get_operations(self, address, cursor='now'): res_list = [] for i in range(50): params = { 'order': 'desc', 'limit': '200', 'cursor': cursor, } res = self.client.account_operations(address, params=params) pprint(res) if res: target = res.get('_embedded', '').get('records', '') if target: res_list.extend( [i for i in target if i.get('type', '') == 'payment']) last_elm = target[-1] cursor = last_elm['paging_token'] else: break return res_list
class SDK(object): """ The :class:`~kin.SDK` class is the primary interface to the KIN Python SDK based on Stellar Blockchain. It maintains a connection context with a Horizon node and hides all the specifics of dealing with Stellar REST API. """ def __init__(self, base_seed='', horizon_endpoint_uri='', network='PUBLIC', channel_seeds=[]): """Create a new instance of the KIN SDK for Stellar. If seed is not provided, the SDK can still be used in "anonymous" mode with only the following functions available: - get_address_lumen_balance - get_address_kin_balance - check_kin_trusted - check_account_exists - get_account_data - get_transaction_data - monitor_address_transactions :param str seed: a seed to initialize the sdk wallet account with. If not provided, the wallet will not be initialized and methods needing the wallet will raise exception. :param str horizon_endpoint_uri: a Horizon endpoint. If not provided, a default endpoint will be used, either a testnet or pubnet, depending on the `network` parameter. :param str network: either PUBLIC or TESTNET, will set the Horizon endpoint in the absence of `horizon_endpoint_uri`. :param list channel_seeds: a list of channels to sign transactions with. More channels means less blocking on transactions and better response time. :return: An instance of the SDK. :rtype: :class:`~kin.SDK` :raises: :class:`~kin.SdkConfigurationError` if some of the configuration parameters are invalid. """ self.network = network if not self.network: self.network = 'PUBLIC' if horizon_endpoint_uri: self.horizon = Horizon(horizon_endpoint_uri) else: if self.network == 'TESTNET': self.horizon = horizon_testnet() else: self.horizon = horizon_livenet() # check Horizon connection try: self.horizon.query('') except Exception as e: raise SdkConfigurationError('cannot connect to horizon') # init sdk account base_keypair if a base_seed is supplied self.base_keypair = None if base_seed: try: validate_seed(base_seed) except ValueError: raise SdkConfigurationError('invalid base seed: {}'.format(base_seed)) self.base_keypair = Keypair.from_seed(base_seed) # check channel seeds if channel_seeds: for channel_seed in channel_seeds: try: validate_seed(channel_seed) except ValueError: raise SdkConfigurationError('invalid channel seed: {}'.format(channel_seed)) else: channel_seeds = [base_seed] # init channel manager self.channel_manager = ChannelManager(base_seed, channel_seeds, self.network, self.horizon.horizon) def get_address(self): """Get the address of the SDK wallet account. The wallet is configured by a seed supplied during SDK initialization. :return: public address of the wallet. :rtype: str :raises: :class:`~kin.SdkConfigurationError`: if the SDK wallet is not configured. """ if not self.base_keypair: raise SdkNotConfiguredError('address not configured') return self.base_keypair.address().decode() def get_lumen_balance(self): """Get lumen balance of the SDK wallet. The wallet is configured by a seed supplied during SDK initialization. :return: : the balance in lumens. :rtype: Decimal :raises: :class:`~kin.SdkConfigurationError`: if the SDK wallet is not configured. """ return self.get_address_lumen_balance(self.get_address()) def get_kin_balance(self): """Get KIN balance of the SDK wallet. The wallet is configured by a seed supplied during SDK initialization. :return: : the balance in KIN. :rtype: Decimal :raises: :class:`~kin.SdkConfigurationError`: if the SDK wallet is not configured. """ return self.get_address_kin_balance(self.get_address()) def get_address_lumen_balance(self, address): """Get lumen balance of the account identified by the provided address. :param: str address: the address of the account to query. :return: the lumen balance of the account. :rtype: Decimal :raises: ValueError: if the supplied address has a wrong format. """ return self.get_address_asset_balance(address, Asset.native()) def get_address_kin_balance(self, address): """Get KIN balance of the account identified by the provided address. :param: str address: the address of the account to query. :return: : the balance in KIN of the account. :rtype: Decimal :raises: ValueError: if the supplied address has a wrong format. """ return self.get_address_asset_balance(address, KIN_ASSET) def get_address_asset_balance(self, address, asset): """Get asset balance of the account identified by the provided address. :param: str address: the address of the account to query. :return: : the balance in asset units of the account. :rtype: Decimal :raises: ValueError: if the supplied address has a wrong format. """ if not asset.is_native(): try: validate_address(asset.issuer) except ValueError: raise ValueError('asset issuer invalid') acc_data = self.get_account_data(address) for balance in acc_data.balances: if (balance.asset_type == 'native' and asset.code == 'XLM') \ or (balance.asset_code == asset.code and balance.asset_issuer == asset.issuer): return balance.balance return 0 def create_account(self, address, starting_balance=MIN_ACCOUNT_BALANCE, memo_text=None): """Create a stellar account identified by the provided address. :param str address: the address of the account to create. :param number starting_balance: the starting balance of the account. If not provided, a default MIN_ACCOUNT_BALANCE will be used. :param str memo_text: a text to put into transaction memo. :return: transaction hash :rtype: str :raises: :class:`~kin.SdkConfigurationError` if the SDK wallet is not configured. :raises: ValueError: if the supplied address has a wrong format. """ if not self.base_keypair: raise SdkNotConfiguredError('address not configured') validate_address(address) return self.channel_manager.send_transaction(lambda builder: partial(builder.append_create_account_op, address, starting_balance), memo_text=memo_text) def trust_asset(self, asset, limit=None, memo_text=None): """Establish a trustline from the SDK wallet to the asset issuer. :param asset: the asset to establish a trustline to. :rtype: :class:`~stellar_base.asset.Asset` :param number limit: trustline limit. :param str memo_text: a text to put into transaction memo. :return: transaction hash :rtype: str :raises: :class:`~kin.SdkConfigurationError` if the SDK wallet is not configured. :raises: ValueError: if the issuer address has a wrong format. """ if not self.base_keypair: raise SdkNotConfiguredError('address not configured') if not asset.is_native(): try: validate_address(asset.issuer) except ValueError: raise ValueError('asset issuer invalid') return self.channel_manager.send_transaction(lambda builder: partial(builder.append_trust_op, asset.issuer, asset.code, limit=limit), memo_text=memo_text) def check_kin_trusted(self, address): """Check if the account has a trustline to KIN asset. :param str address: the account address to query. :return: True if the account has a trustline to KIN asset. :rtype: boolean :raises: ValueError: if the supplied address has a wrong format. """ return self.check_asset_trusted(address, KIN_ASSET) def check_asset_trusted(self, address, asset): """Check if the account has a trustline to the provided asset. :param str address: the account address to query. :return: True if the account has a trustline to the asset. :rtype: boolean :raises: ValueError: if the supplied address has a wrong format. :raises: ValueError: if the asset issuer address has a wrong format. """ if not asset.is_native(): try: validate_address(asset.issuer) except ValueError: raise ValueError('asset issuer invalid') acc_data = self.get_account_data(address) for balance in acc_data.balances: if balance.asset_code == asset.code and balance.asset_issuer == asset.issuer: return True return False def check_account_exists(self, address): """Check whether the account identified by the provided address exists. :param str address: the account address to query. :return: True if the account exists. :raises: ValueError: if the supplied address has a wrong format. """ try: self.get_account_data(address) return True except SdkHorizonError as se: if se.status == 404: return False raise def send_lumens(self, address, amount, memo_text=None): """Send lumens to the account identified by the provided address. :param str address: the account to send lumens to. :param number amount: the number of lumens to send. :param str memo_text: a text to put into transaction memo. :return: transaction hash :rtype: str :raises: :class:`~kin.SdkConfigurationError` if the SDK wallet is not configured. :raises: ValueError: if the provided address has a wrong format. :raises: ValueError: if the amount is not positive. """ return self.send_asset(address, Asset.native(), amount, memo_text) def send_kin(self, address, amount, memo_text=None): """Send KIN to the account identified by the provided address. :param str address: the account to send KIN to. :param number amount: the number of KIN to send. :param str memo_text: a text to put into transaction memo. :return: transaction hash :rtype: str :raises: :class:`~kin.SdkConfigurationError` if the SDK wallet is not configured. :raises: ValueError: if the provided address has a wrong format. :raises: ValueError: if the amount is not positive. """ return self.send_asset(address, KIN_ASSET, amount, memo_text) def send_asset(self, address, asset, amount, memo_text=None): """Send asset to the account identified by the provided address. :param str address: the account to send asset to. :param number amount: the asset amount to send. :param str memo_text: a text to put into transaction memo. :return: transaction hash :rtype: str :raises: :class:`~kin.SdkConfigurationError` if the SDK wallet is not configured. :raises: ValueError: if the provided address has a wrong format. :raises: ValueError: if the asset issuer address has a wrong format. :raises: ValueError: if the amount is not positive. """ if not self.base_keypair: raise SdkNotConfiguredError('address not configured') validate_address(address) if amount <= 0: raise ValueError('amount must be positive') if not asset.is_native(): try: validate_address(asset.issuer) except ValueError: raise ValueError('asset issuer invalid') return self.channel_manager.send_transaction(lambda builder: partial(builder.append_payment_op, address, amount, asset_type=asset.code, asset_issuer=asset.issuer), memo_text=memo_text) def get_account_data(self, address): """Gets account data. :param str address: the account to query. :return: account data :rtype: :class:`~kin.AccountData` :raises: ValueError: if the provided address has a wrong format. """ validate_address(address) acc = self.horizon.account(address) check_horizon_reply(acc) return AccountData(acc, strict=False) def get_transaction_data(self, tx_hash): """Gets transaction data. :param str tx_hash: transaction hash. :return: transaction data :rtype: :class:`~kin.TransactionData` """ # get transaction data tx = self.horizon.transaction(tx_hash) check_horizon_reply(tx) # get transaction operations tx_ops = self.horizon.transaction_operations(tx['hash']) # TODO: max 50, paged? check_horizon_reply(tx_ops) tx['operations'] = tx_ops['_embedded']['records'] return TransactionData(tx, strict=False) def monitor_transactions(self, callback_fn): """Monitor transactions related to the SDK wallet account. NOTE: the functions starts a background thread. :param callback_fn: the function to call on each received transaction. The function has one parameter, which is a transaction data object. """ if not self.base_keypair: raise SdkNotConfiguredError('address not configured') self.monitor_address_transactions(self.get_address(), callback_fn) def monitor_address_transactions(self, address, callback_fn): """Monitor transactions related to the account identified by a provided address. NOTE: the functions starts a background thread. :param callback_fn: the function to call on each received transaction. The function has one parameter, which is a transaction data object. :raises: ValueError: if the provided address has a wrong format. """ validate_address(address) # make the SSE request synchronous (will throw errors in the current thread) events = self.horizon.account_transactions(address, sse=True) # TODO: last_id support # check_horizon_reply(events) # NOTE: not a Horizon reply! # TODO: why not consistent # asynchronous event processor def event_processor(): import json for event in events: if event.event == 'message': try: tx = json.loads(event.data) # get transaction operations tx_ops = self.horizon.transaction_operations(tx['hash']) # TODO: max 50, paged? check_horizon_reply(tx_ops) tx['operations'] = tx_ops['_embedded']['records'] tx_data = TransactionData(tx, strict=False) callback_fn(tx_data) except Exception as e: logger.exception(e) continue # start monitoring thread import threading t = threading.Thread(target=event_processor) t.daemon = True t.start()
def __init__(self, base_seed='', horizon_endpoint_uri='', network='PUBLIC', channel_seeds=[]): """Create a new instance of the KIN SDK for Stellar. If seed is not provided, the SDK can still be used in "anonymous" mode with only the following functions available: - get_address_lumen_balance - get_address_kin_balance - check_kin_trusted - check_account_exists - get_account_data - get_transaction_data - monitor_address_transactions :param str seed: a seed to initialize the sdk wallet account with. If not provided, the wallet will not be initialized and methods needing the wallet will raise exception. :param str horizon_endpoint_uri: a Horizon endpoint. If not provided, a default endpoint will be used, either a testnet or pubnet, depending on the `network` parameter. :param str network: either PUBLIC or TESTNET, will set the Horizon endpoint in the absence of `horizon_endpoint_uri`. :param list channel_seeds: a list of channels to sign transactions with. More channels means less blocking on transactions and better response time. :return: An instance of the SDK. :rtype: :class:`~kin.SDK` :raises: :class:`~kin.SdkConfigurationError` if some of the configuration parameters are invalid. """ self.network = network if not self.network: self.network = 'PUBLIC' if horizon_endpoint_uri: self.horizon = Horizon(horizon_endpoint_uri) else: if self.network == 'TESTNET': self.horizon = horizon_testnet() else: self.horizon = horizon_livenet() # check Horizon connection try: self.horizon.query('') except Exception as e: raise SdkConfigurationError('cannot connect to horizon') # init sdk account base_keypair if a base_seed is supplied self.base_keypair = None if base_seed: try: validate_seed(base_seed) except ValueError: raise SdkConfigurationError('invalid base seed: {}'.format(base_seed)) self.base_keypair = Keypair.from_seed(base_seed) # check channel seeds if channel_seeds: for channel_seed in channel_seeds: try: validate_seed(channel_seed) except ValueError: raise SdkConfigurationError('invalid channel seed: {}'.format(channel_seed)) else: channel_seeds = [base_seed] # init channel manager self.channel_manager = ChannelManager(base_seed, channel_seeds, self.network, self.horizon.horizon)
Created on Thu Oct 26 22:57:06 2017 @author: 1Hr1619SxTuTBC3qYZJ1rkfAxrvWnt7bt3 """ #%% from stellar_base.address import Address from stellar_base.operation import ChangeTrust from stellar_base.asset import Asset from stellar_base.horizon import horizon_livenet from stellar_base.horizon import Horizon from stellar_base.transaction_envelope import TransactionEnvelope as Te from stellar_base.transaction import Transaction from stellar_base.keypair import Keypair from stellar_base.operation import Payment horizon = Horizon('https://cryptodealer.hk') #%% import os import hashlib import json import binascii import sys #%% from trezorlib.client import TrezorClient from trezorlib.transport_hid import HidTransport #%%Interacting with Local Trezor hardware