Skip to content

Commit a4930eb

Browse files
authored
Merge pull request #32 from StellarCN/dev
rewrite builder and fix bugs. support new manage_data operation.
2 parents 9c6029a + b36f627 commit a4930eb

31 files changed

+6127
-5713
lines changed

README.md

+151-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,158 @@
1+
12
[![Build Status](https://travis-ci.org/StellarCN/py-stellar-base.svg)](https://travis-ci.org/StellarCN/py-stellar-base)
23

34
# install
4-
`pip install stellar-base.whl`
5+
pip install stellar-base.whl
56

67

78
# usage
89

10+
## Create a Stellar keypair?
11+
```python
12+
from stellar_base.keypair import Keypair
13+
kp = Keypair.random()
14+
```
15+
**or**
16+
```python
17+
from __future__ import unicode_literals
18+
master = u'中文'.encode('utf-8')
19+
kp = Keypair.deterministic(master)
20+
```
21+
then we can get key/secret from random:
22+
23+
publickey = kp.address().decode()
24+
secret = kp.seed().decode()
25+
26+
27+
let's start with my favourite keypair in TESTNET.
28+
29+
publickey = 'GDVDKQFP665JAO7A2LSHNLQIUNYNAAIGJ6FYJVMG4DT3YJQQJSRBLQDG'
30+
secret = 'SCVLSUGYEAUC4MVWJORB63JBMY2CEX6ATTJ5MXTENGD3IELUQF4F6HUB'
31+
32+
33+
34+
35+
##Account
36+
37+
### base info
38+
```python
39+
from stellar_base.account import Account
40+
publickey = 'GDVDKQFP665JAO7A2LSHNLQIUNYNAAIGJ6FYJVMG4DT3YJQQJSRBLQDG'
41+
account = Account(account=publickey)
42+
# account = Account(account=publickey,network='public') for livenet.
43+
account.get()
44+
```
45+
now you can check account.`balance` ,`sequence` ,`flags` ,`signers`, `manage_data` etc.
46+
47+
### check payments
48+
`account.payments()`will give you latest 10 payments.
49+
50+
there are three params using for query : `limit`, `order` and `cursor`(paging_token). and the default value for them is 10, asc and 0
51+
52+
so need check payments after a specific cursor?try `account.payments(cursor='4225135422738433',limit=20,order=asc)`
53+
54+
Horizon have SSE support for push data ,if you really want, use like this: `account.payment(sse=True,cursor='4225135422738433')`
55+
56+
###like check payments, you can check `transactions`,`effects`,`offers`,and `operations`.
57+
remember , offers have not SSE support.
58+
59+
60+
## Transaction Builder
61+
62+
### create a Transaction Builder at first
63+
64+
from stellar_base.builder import Builder
65+
builder = Builder(secret=secret)
66+
# builder = Builder(secret=secret, network='public') for LIVENET.
67+
68+
### operations
69+
how about make a tips to bob?
70+
71+
bob_address = 'GABCDEFGHIJKLMNOPQRSTUVW'
72+
builder.append_payment_op(bob_address,'100','XLM')
73+
or
74+
75+
CNY_ISSUER='GCNYISSUERABCDEFGHIJKLMNOPQ'
76+
builder.append_payment_op(bob_address,'100','CNY',CNY_ISSUER)
77+
78+
### then maybe need carry a message
79+
80+
builder.add_text_memo('Have a nice day!') # string length <= 28 bytes
81+
82+
### sign & sumbit
83+
84+
builder.sign()
85+
builder.sumbit()
86+
87+
Done.
88+
89+
### sign a muilt-sig transaction
90+
91+
you get a xdr string (or transaction envlope xdr)from a friend or partner ,which decribe a multi-sig transaction .
92+
They need you sign on it too.
93+
94+
builder = Builder(secret=secret)
95+
# or builder = Builder(secret=secret, network='public') for LIVENET.
96+
builder.import_from_xdr(xdr_string)
97+
builder.sign()
98+
builder.to_xdr() # generate new xdr string
99+
# or builder.submit() #submit to stellar network
100+
101+
102+
103+
## A payment example without wrapper
104+
105+
106+
from stellar_base.keypair import Keypair
107+
from stellar_base.asset import Asset
108+
from stellar_base.operation import Payment
109+
from stellar_base.transaction import Transaction
110+
from stellar_base.transaction_envelope import TransactionEnvelope as Te
111+
from stellar_base.memo import TextMemo
112+
from stellar_base.horizon import horizon_testnet, horizon_pubic
113+
114+
alice_seed = 'SAZJ3EDATROKTNNN4WZBZPRC34AN5WR43VEHAFKT5D66UEZTKDNKUHOK'
115+
bob_address = 'GDLP3SP4WP72L4BAJWZUDZ6SAYE4NAWILT5WQDS7RWC4XCUNUQDRB2A4'
116+
CNY_ISSUER = 'GDVDKQFP665JAO7A2LSHNLQIUNYNAAIGJ6FYJVMG4DT3YJQQJSRBLQDG'
117+
amount = '100'
118+
119+
Alice = Keypair.from_seed(alice_seed)
120+
horizon = horizon_testnet()
121+
122+
asset = Asset('CNY', CNY_ISSUER)
123+
# create op
124+
op = Payment({
125+
# 'source' : Alice.address().decode(),
126+
'destination': bob_address,
127+
'asset': asset,
128+
'amount': amount
129+
})
130+
# create a memo
131+
msg = TextMemo('Have a nice day!')
132+
133+
# get sequence of Alice
134+
sequence = horizon.account(Alice.address()).get('sequence')
135+
136+
# construct Tx
137+
tx = Transaction(
138+
source=Alice.address().decode(),
139+
opts={
140+
'sequence': sequence,
141+
# 'timeBounds': [],
142+
'memo': msg,
143+
# 'fee': 100,
144+
'operations': [
145+
op,
146+
],
147+
},
148+
)
149+
150+
151+
# build envelope
152+
envelope = Te(tx=tx, opts={"network_id": "TESTNET"})
153+
# sign
154+
envelope.sign(Alice)
155+
# submit
156+
xdr = envelope.xdr()
157+
horizon.submit(xdr)
158+

setup.py

+8-6
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1+
# coding: utf-8
2+
import codecs
3+
14
from setuptools import setup, find_packages
25

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

69
setup(
710
name='stellar-base',
8-
version='0.0.1',
11+
version='0.1.0',
912
description='stellar-base in python.',
1013
long_description=long_description,
1114
url='http://github.com/stellarCN/py-stellar-base/',
@@ -21,14 +24,13 @@
2124
'License :: OSI Approved :: Apache License',
2225
'Operating System :: OS Independent',
2326
'Programming Language :: Python',
24-
# 'Programming Language :: Python :: 2',
25-
# 'Programming Language :: Python :: 2.6',
26-
# 'Programming Language :: Python :: 2.7',
27+
'Programming Language :: Python :: 2.7',
2728
'Programming Language :: Python :: 3',
2829
'Programming Language :: Python :: 3.4',
30+
'Programming Language :: Python :: 3.5',
2931
'Topic :: Software Development :: Libraries :: Python Modules',
3032
],
3133
install_requires=[
32-
'ed25519', 'crc16', 'requests', 'SSEClient', 'base58'
34+
'ed25519', 'crc16', 'requests', 'SSEClient', 'numpy'
3335
]
3436
)

stellar_base/address.py

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# encoding: utf-8
2+
3+
import requests
4+
5+
from .horizon import Horizon
6+
from .keypair import Keypair
7+
from .utils import AccountNotExistError, NotValidParamError
8+
from .horizon import HORIZON_LIVE, HORIZON_TEST
9+
10+
11+
class Address(object):
12+
""" check address info from stellar network using horizon rest api or SSE.
13+
14+
"""
15+
16+
def __init__(self, address=None, secret=None, network='TESTNET', horizon=None):
17+
if address is None and secret is None:
18+
raise Exception('oops,need a stellar address or secret')
19+
if address is None and secret is not None:
20+
self.address = Keypair.from_seed(secret).address().decode()
21+
else:
22+
self.address = address
23+
self.secret = secret
24+
25+
if network.upper() != 'PUBLIC':
26+
self.network = 'TESTNET'
27+
else:
28+
self.network = 'PUBLIC'
29+
if horizon:
30+
self.horizon = Horizon(horizon)
31+
elif network.upper() == 'PUBLIC':
32+
self.horizon = Horizon(HORIZON_LIVE)
33+
else:
34+
self.horizon = Horizon(HORIZON_TEST)
35+
36+
self.sequence = None
37+
self.balances = None
38+
self.paging_token = None
39+
self.thresholds = None
40+
self.flags = None
41+
self.signers = None
42+
self.data = None
43+
44+
def get(self):
45+
try:
46+
acc = self.horizon.account(self.address)
47+
if acc.get('sequence'):
48+
self.sequence = acc.get('sequence')
49+
self.balances = acc.get('balances')
50+
self.paging_token = acc.get('paging_token')
51+
self.thresholds = acc.get('thresholds')
52+
self.flags = acc.get('flags')
53+
self.signers = acc.get('signers')
54+
self.data = acc.get('data')
55+
elif acc.get('status') == 404:
56+
raise AccountNotExistError(acc.get('title'))
57+
else:
58+
raise Exception(acc.get('detail'))
59+
except requests.ConnectionError:
60+
raise Exception('network problem')
61+
62+
def payments(self, sse=False, **kwargs):
63+
check_params(kwargs)
64+
return self.horizon.account_payments(self.address, params=kwargs, sse=sse)
65+
66+
def offers(self, **kwargs):
67+
check_params(kwargs)
68+
return self.horizon.account_offers(self.address, params=kwargs)
69+
70+
def transactions(self, sse=False, **kwargs):
71+
check_params(kwargs)
72+
return self.horizon.account_transactions(self.address, params=kwargs, sse=sse)
73+
74+
def operations(self, sse=False, **kwargs):
75+
check_params(kwargs)
76+
return self.horizon.account_operations(self.address, params=kwargs, sse=sse)
77+
78+
def effects(self, sse=False, **kwargs):
79+
check_params(kwargs)
80+
return self.horizon.account_effects(self.address, params=kwargs, sse=sse)
81+
82+
83+
def check_params(data):
84+
params = {'cursor', 'limit', 'order'}
85+
for key in data.keys():
86+
if key not in params:
87+
raise NotValidParamError('not valid params')

stellar_base/asset.py

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
# coding: utf-8
22

33
from .utils import XdrLengthError, account_xdr_object, encode_check
4-
from .stellarxdr import StellarXDR_pack as Xdr
4+
from .stellarxdr import Xdr
5+
import base64
56

67

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

55+
def xdr(self):
56+
asset = Xdr.StellarXDRPacker()
57+
asset.pack_Asset(self.to_xdr_object())
58+
return base64.b64encode(asset.get_buffer())
59+
5460
@classmethod
5561
def from_xdr_object(cls, asset_xdr_object):
5662
if asset_xdr_object.type == Xdr.const.ASSET_TYPE_NATIVE:

0 commit comments

Comments
 (0)