-
Notifications
You must be signed in to change notification settings - Fork 170
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #32 from StellarCN/dev
rewrite builder and fix bugs. support new manage_data operation.
- Loading branch information
Showing
31 changed files
with
6,127 additions
and
5,713 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.