Skip to content

rewrite builder and fix bugs. support new manage_data operation. #32

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 22 commits into from
Jun 15, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
152 changes: 151 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,158 @@

[![Build Status](https://travis-ci.org/StellarCN/py-stellar-base.svg)](https://travis-ci.org/StellarCN/py-stellar-base)

# install
`pip install stellar-base.whl`
pip install stellar-base.whl


# usage

## Create a Stellar keypair?
```python
from stellar_base.keypair import Keypair
kp = Keypair.random()
```
**or**
```python
from __future__ import unicode_literals
master = u'中文'.encode('utf-8')
kp = Keypair.deterministic(master)
```
then we can get key/secret from random:

publickey = kp.address().decode()
secret = kp.seed().decode()


let's start with my favourite keypair in TESTNET.

publickey = 'GDVDKQFP665JAO7A2LSHNLQIUNYNAAIGJ6FYJVMG4DT3YJQQJSRBLQDG'
secret = 'SCVLSUGYEAUC4MVWJORB63JBMY2CEX6ATTJ5MXTENGD3IELUQF4F6HUB'




##Account

### base info
```python
from stellar_base.account import Account
publickey = 'GDVDKQFP665JAO7A2LSHNLQIUNYNAAIGJ6FYJVMG4DT3YJQQJSRBLQDG'
account = Account(account=publickey)
# account = Account(account=publickey,network='public') for livenet.
account.get()
```
now you can check account.`balance` ,`sequence` ,`flags` ,`signers`, `manage_data` etc.

### check payments
`account.payments()`will give you latest 10 payments.

there are three params using for query : `limit`, `order` and `cursor`(paging_token). and the default value for them is 10, asc and 0

so need check payments after a specific cursor?try `account.payments(cursor='4225135422738433',limit=20,order=asc)`

Horizon have SSE support for push data ,if you really want, use like this: `account.payment(sse=True,cursor='4225135422738433')`

###like check payments, you can check `transactions`,`effects`,`offers`,and `operations`.
remember , offers have not SSE support.


## Transaction Builder

### create a Transaction Builder at first

from stellar_base.builder import Builder
builder = Builder(secret=secret)
# builder = Builder(secret=secret, network='public') for LIVENET.

### operations
how about make a tips to bob?

bob_address = 'GABCDEFGHIJKLMNOPQRSTUVW'
builder.append_payment_op(bob_address,'100','XLM')
or

CNY_ISSUER='GCNYISSUERABCDEFGHIJKLMNOPQ'
builder.append_payment_op(bob_address,'100','CNY',CNY_ISSUER)

### then maybe need carry a message

builder.add_text_memo('Have a nice day!') # string length <= 28 bytes

### sign & sumbit

builder.sign()
builder.sumbit()

Done.

### sign a muilt-sig transaction

you get a xdr string (or transaction envlope xdr)from a friend or partner ,which decribe a multi-sig transaction .
They need you sign on it too.

builder = Builder(secret=secret)
# or builder = Builder(secret=secret, network='public') for LIVENET.
builder.import_from_xdr(xdr_string)
builder.sign()
builder.to_xdr() # generate new xdr string
# or builder.submit() #submit to stellar network



## A payment example without wrapper


from stellar_base.keypair import Keypair
from stellar_base.asset import Asset
from stellar_base.operation import Payment
from stellar_base.transaction import Transaction
from stellar_base.transaction_envelope import TransactionEnvelope as Te
from stellar_base.memo import TextMemo
from stellar_base.horizon import horizon_testnet, horizon_pubic

alice_seed = 'SAZJ3EDATROKTNNN4WZBZPRC34AN5WR43VEHAFKT5D66UEZTKDNKUHOK'
bob_address = 'GDLP3SP4WP72L4BAJWZUDZ6SAYE4NAWILT5WQDS7RWC4XCUNUQDRB2A4'
CNY_ISSUER = 'GDVDKQFP665JAO7A2LSHNLQIUNYNAAIGJ6FYJVMG4DT3YJQQJSRBLQDG'
amount = '100'

Alice = Keypair.from_seed(alice_seed)
horizon = horizon_testnet()

asset = Asset('CNY', CNY_ISSUER)
# create op
op = Payment({
# 'source' : Alice.address().decode(),
'destination': bob_address,
'asset': asset,
'amount': amount
})
# create a memo
msg = TextMemo('Have a nice day!')

# get sequence of Alice
sequence = horizon.account(Alice.address()).get('sequence')

# construct Tx
tx = Transaction(
source=Alice.address().decode(),
opts={
'sequence': sequence,
# 'timeBounds': [],
'memo': msg,
# 'fee': 100,
'operations': [
op,
],
},
)


# build envelope
envelope = Te(tx=tx, opts={"network_id": "TESTNET"})
# sign
envelope.sign(Alice)
# submit
xdr = envelope.xdr()
horizon.submit(xdr)

14 changes: 8 additions & 6 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
# coding: utf-8
import codecs

from setuptools import setup, find_packages

with open('README.md') as file:
with codecs.open('README.md', encoding='utf-8') as file:
long_description = file.read()

setup(
name='stellar-base',
version='0.0.1',
version='0.1.0',
description='stellar-base in python.',
long_description=long_description,
url='http://github.com/stellarCN/py-stellar-base/',
Expand All @@ -21,14 +24,13 @@
'License :: OSI Approved :: Apache License',
'Operating System :: OS Independent',
'Programming Language :: Python',
# 'Programming Language :: Python :: 2',
# 'Programming Language :: Python :: 2.6',
# 'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Topic :: Software Development :: Libraries :: Python Modules',
],
install_requires=[
'ed25519', 'crc16', 'requests', 'SSEClient', 'base58'
'ed25519', 'crc16', 'requests', 'SSEClient', 'numpy'
]
)
87 changes: 87 additions & 0 deletions stellar_base/address.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# encoding: utf-8

import requests

from .horizon import Horizon
from .keypair import Keypair
from .utils import AccountNotExistError, NotValidParamError
from .horizon import HORIZON_LIVE, HORIZON_TEST


class Address(object):
""" check address info from stellar network using horizon rest api or SSE.

"""

def __init__(self, address=None, secret=None, network='TESTNET', horizon=None):
if address is None and secret is None:
raise Exception('oops,need a stellar address or secret')
if address is None and secret is not None:
self.address = Keypair.from_seed(secret).address().decode()
else:
self.address = address
self.secret = secret

if network.upper() != 'PUBLIC':
self.network = 'TESTNET'
else:
self.network = 'PUBLIC'
if horizon:
self.horizon = Horizon(horizon)
elif network.upper() == 'PUBLIC':
self.horizon = Horizon(HORIZON_LIVE)
else:
self.horizon = Horizon(HORIZON_TEST)

self.sequence = None
self.balances = None
self.paging_token = None
self.thresholds = None
self.flags = None
self.signers = None
self.data = None

def get(self):
try:
acc = self.horizon.account(self.address)
if acc.get('sequence'):
self.sequence = acc.get('sequence')
self.balances = acc.get('balances')
self.paging_token = acc.get('paging_token')
self.thresholds = acc.get('thresholds')
self.flags = acc.get('flags')
self.signers = acc.get('signers')
self.data = acc.get('data')
elif acc.get('status') == 404:
raise AccountNotExistError(acc.get('title'))
else:
raise Exception(acc.get('detail'))
except requests.ConnectionError:
raise Exception('network problem')

def payments(self, sse=False, **kwargs):
check_params(kwargs)
return self.horizon.account_payments(self.address, params=kwargs, sse=sse)

def offers(self, **kwargs):
check_params(kwargs)
return self.horizon.account_offers(self.address, params=kwargs)

def transactions(self, sse=False, **kwargs):
check_params(kwargs)
return self.horizon.account_transactions(self.address, params=kwargs, sse=sse)

def operations(self, sse=False, **kwargs):
check_params(kwargs)
return self.horizon.account_operations(self.address, params=kwargs, sse=sse)

def effects(self, sse=False, **kwargs):
check_params(kwargs)
return self.horizon.account_effects(self.address, params=kwargs, sse=sse)


def check_params(data):
params = {'cursor', 'limit', 'order'}
for key in data.keys():
if key not in params:
raise NotValidParamError('not valid params')
8 changes: 7 additions & 1 deletion stellar_base/asset.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# coding: utf-8

from .utils import XdrLengthError, account_xdr_object, encode_check
from .stellarxdr import StellarXDR_pack as Xdr
from .stellarxdr import Xdr
import base64


class Asset(object):
Expand Down Expand Up @@ -51,6 +52,11 @@ def to_xdr_object(self):
xdr_type = Xdr.const.ASSET_TYPE_CREDIT_ALPHANUM12
return Xdr.types.Asset(type=xdr_type, alphaNum12=x)

def xdr(self):
asset = Xdr.StellarXDRPacker()
asset.pack_Asset(self.to_xdr_object())
return base64.b64encode(asset.get_buffer())

@classmethod
def from_xdr_object(cls, asset_xdr_object):
if asset_xdr_object.type == Xdr.const.ASSET_TYPE_NATIVE:
Expand Down
Loading