예제 #1
0
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)
예제 #2
0
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)
예제 #4
0
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)
예제 #5
0
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)
예제 #6
0
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
예제 #7
0
    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)
예제 #8
0
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
예제 #9
0
 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'
예제 #10
0
    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
예제 #11
0
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
예제 #12
0
    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
예제 #13
0
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)
예제 #14
0
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)
예제 #15
0
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)
예제 #16
0
# 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
예제 #17
0
파일: xlm.py 프로젝트: buyongji/wallet
 def __init__(self, rpc_uri, timeout):
     self.client = Horizon(horizon=rpc_uri, timeout=timeout)  # 测试节点
     self.rpc_uri = rpc_uri
예제 #18
0
파일: xlm.py 프로젝트: buyongji/wallet
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
예제 #19
0
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()
예제 #20
0
    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)
예제 #21
0
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