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 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 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
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()