.. _quick_start:
***********
Quick Start
***********
Stellar Guides
==============
At the absolute basics, you'll want to read up on `Stellar's Documentation
Guides `_, as it contains a lot of
information on the concepts used below (Transactions, Payments, Operations,
KeyPairs, etc.).
Alright, let's get started!
===========================
First, you'll want to create a Stellar key pair. There are 2 methods for
generating a key pair:
Random Key Generation
---------------------
Simply use :meth:`Keypair.random ` to
generate the object like so:
.. code-block:: python
from stellar_base.keypair import Keypair
kp = Keypair.random()
Deterministic generation
------------------------
Or, generate the key pair is deterministically from a mnemonic string, also
known as "seed phrase". This can be useful for backing up the passphrase on
paper and using it later, or by making it easier to memorize than the secret
seed.
First you'll need to generate a mnemonic string:
.. code-block:: python
from stellar_base.utils import StellarMnemonic
# Here we use Chinese, but English is the default language.
sm = StellarMnemonic("chinese")
secret_phrase = sm.generate()
You can also use your own mnemonic string instead of a generated one. Once
you've created your secret phrase, you should either write your phrase down or
memorize it. You should not share your mnemonic string with anyone.
From here, we use :meth:`Keypair.deterministic
` to generate the keypair from
your secret phrase:
.. code-block:: python
kp = Keypair.deterministic(secret_phrase, lang='chinese')
You can even create multiple key pairs from the same phrase, using a different
index with each call. For example:
.. code-block:: python
kp1 = Keypair.deterministic(secret_phrase, lang='chinese', index=1)
kp2 = Keypair.deterministic(secret_phrase, lang='chinese', index=2)
From the generated :class:`Keypair ` object, you
can easily access your public and private key.
.. code-block:: python
publickey = kp.address().decode()
seed = kp.seed().decode()
Your master public key is also your account address. If someone needs to send
you a transaction, you should share your public key with them. However, your
secret seed should always remain locally on your computer, and it should never
be transmitted over the internet.
If you ever forget or lose the public key, you can regenerate the key pair from
the your secret seed:
.. code-block:: python
from stellar_base.keypair import Keypair
kp = Keypair.from_seed(seed)
Both the public key and the secret seed can be regenerated via the secret
phrase if you used on.
.. code-block:: python
from stellar_base.keypair import Keypair
seed_phrase = '...' # the word sequence that you wrote down or memorized
kp = Keypair.deterministic(seed_phrase, lang='chinese')
However, if you used a random generator, it is important to never lose your
seed - otherwise you won't be able to send transactions, and many other
operations!
Here is a sample key pair in Stellar Development Foundation's (SDF) TESTNET;
let's use them in the following steps:
.. code-block:: python
publickey = 'GDVDKQFP665JAO7A2LSHNLQIUNYNAAIGJ6FYJVMG4DT3YJQQJSRBLQDG'
seed = 'SCVLSUGYEAUC4MVWJORB63JBMY2CEX6ATTJ5MXTENGD3IELUQF4F6HUB'
Create An Account
=================
Now, in order to create an account, you need to run a :class:`CreateAccount
` operation with your new account ID.
Due to `Stellar's account minimums
`_,
you'll need to transfer the minimum account balance from another account with
the create account operation. As of this writing, minimum balance is ``1 XLM (2
x 0.5 Base Reserve)``, and is subject to change.
Using The SDF Testnet
---------------------
If you want to play in the Stellar test network, you can ask our `Friendbot
`_
to create an account for you as shown below:
.. code-block:: python
import requests
publickey = kp.address().decode()
url = 'https://friendbot.stellar.org'
r = requests.get(url, params={'addr': publickey})
Using The Stellar Live Network
------------------------------
On the other hand, if you would like to create an account on the live network,
you should buy some Stellar Lumens from an exchange. When you withdraw the
Lumens into your new account, the exchange will automatically create the
account for you. However, if you want to create an account from another
account of your own, here's an example of how to do so:
.. code-block:: python
from stellar_base.keypair import Keypair
from stellar_base.operation import CreateAccount, 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_livenet
# This creates a new Horizon Livenet instance
horizon = horizon_livenet()
# This is the seed (the StrKey representation of the secret seed that
# generates your private key from your original account that is funding the
# new account in the create account operation. You'll need the seed in order
# to sign off on the transaction. This is the source account.
old_account_seed = "SCVLSUGYEAUC4MVWJORB63JBMY2CEX6ATTJ5MXTENGD3IELUQF4F6HUB"
old_account_keypair = Keypair.from_seed(old_account_seed)
# This is the new account ID (the StrKey representation of your newly
# created public key). This is the destination account.
new_account_addr = "GABRGTDZEDCQ5W663U2EI5KWRSU3EAWJCSI57H7XAMUO5BQRIGNNZGTY"
amount = '1' # Your new account minimum balance (in XLM) to transfer over
# create the CreateAccount operation
op = CreateAccount(
destination=new_account_addr,
starting_balance=amount
)
# create a memo
memo = TextMemo('Hello, StellarCN!')
# Get the current sequence of the source account by contacting Horizon. You
# should also check the response for errors!
# Python 3
sequence = horizon.account(old_account_keypair.address().decode()).get('sequence')
# Python 2
# sequence = horizon.account(old_account_keypair.address()).get('sequence')
# Create a transaction with our single create account operation, with the
# default fee of 100 stroops as of this writing (0.00001 XLM)
tx = Transaction(
source=old_account_keypair.address().decode(),
sequence=sequence,
memo=memo,
operations=[
op,
],
)
# Build a transaction envelope, ready to be signed.
envelope = Te(tx=tx, network_id="PUBLIC")
# 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)
Make sure to look at the response body carefully, as it can be an error or a
successful response.
Looking up Account Details on Horizon
=====================================
Basic Information
-----------------
Once you have the account, you might want to look up its information from
Horizon to verify the network knows about your new account:
.. code-block:: python
from stellar_base.address import Address
publickey = 'GDVDKQFP665JAO7A2LSHNLQIUNYNAAIGJ6FYJVMG4DT3YJQQJSRBLQDG'
address = Address(address=publickey) # See signature for additional args
address.get() # Get the latest information from Horizon
You can now retrieve information for the account's
* Sequence Number
* Balances
* Paging Token
* Thresholds
* Flags
* Signers
* Data
Like so:
.. code-block:: python
print('Balances: {}'.format(address.balances))
print('Sequence Number: {}'.format(address.sequence))
print('Flags: {}'.format(address.flags))
print('Signers: {}'.format(address.signers))
print('Data: {}'.format(address.data))
Most Recent Payments
--------------------
We can check the most recent payments by:
.. code-block:: python
payments = address.payments()
Like many Horizon endpoints, payments is `paginated
`_. You can
get different payments by using the following query parameters: limit, order,
and cursor.
So if you need to check payments after a specific cursor, try:
.. code-block:: python
address.payments(cursor='4225135422738433', limit=20, order='asc')
You can also use `server sent events
`_
if you want to by passing in sse=True on methods that have sse in their
signature.
.. code-block:: python
address.payments(sse=True)
Other Account Attributes
------------------------
Just like payments, there are plenty of other account attributes you can look
up via Horizon:
.. code-block:: python
address.transactions()
address.effects()
address.offers()
address.operations()
Look at the `Horizon API reference
`_ for which
endpoints support SSE.
Building A Transaction
======================
When we created an account, we already created a transaction.
We can build a transaction with a :class:`Builder
`, or with a :class:`Transaction
` object by itself. We recommend you use
the builder, as it handles a lot of the details for you, and you can focus on
the important parameters in each method's signature.
Using a Builder
---------------
Let's send Bob a payment that we owe him. We'd go about this in the following
way:
.. code-block:: python
from stellar_base.builder import Builder
seed = "SCVLSUGYEAUC4MVWJORB63JBMY2CEX6ATTJ5MXTENGD3IELUQF4F6HUB"
builder = Builder(secret=seed)
# builder = Builder(secret=seed, network='public') for LIVENET
bob_address = 'GABRGTDZEDCQ5W663U2EI5KWRSU3EAWJCSI57H7XAMUO5BQRIGNNZGTY'
builder.append_payment_op(bob_address, '100', 'XLM')
builder.add_text_memo('For beers') # string length <= 28 bytes
builder.sign()
# Uses an internal horizon instance to submit over the network
builder.submit()
Or if you want to pay him with CNY:
.. code-block:: python
# This is a stellar issuing account ID for an anchor that issues CNY
CNY_ISSUER = 'GDVDKQFP665JAO7A2LSHNLQIUNYNAAIGJ6FYJVMG4DT3YJQQJSRBLQDG'
builder.append_payment_op(bob_address, '10', 'CNY', CNY_ISSUER)
builder.add_text_memo('For beers') # string length <= 28 bytes
builder.sign()
# Uses an internal horizon instance to submit over the network
builder.submit()
And that's it!
Sometimes, we work with multi-signature transactions that require your
signature in addition to the the account that originally sealed the transaction
in an envelope. Typically you'll get an XDR string that you need to sign. To do
this, you use :meth:`import_from_xdr
` to import it into your builder.
.. code-block:: python
# This is the transaction that you need to add your signature to
xdr_string = 'AAAAAAMTTHkgxQ7b3t00RHVWjKmyAskUkd+f9wMo7oYRQZrcAAAAZAAAAIHlSBzvAAAAAAAAAAAAAAABAAAAAAAAAAoAAAAFaGVsbG8AAAAAAAABAAAAB3N0ZWxsYXIAAAAAAAAAAAA='
builder = Builder(secret=seed)
builder.import_from_xdr(xdr_string)
builder.sign()
xdr_string = builder.gen_xdr()
From here you can pass along your XDR string to anyone else who needs to sign
it, or you can submit it via `builder.submit()` if you're the last to sign.
Using a Transaction Object
--------------------------
Here is a full example of how to make a Transaction from scratch. As you can
see, it requires a lot more imports and knowledge of internal objects, but it
gives you the most flexibility before submitting your transaction over the
wire.
In this example, Alice is sending Bob 100 CNY.
.. code-block:: python
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_livenet
# Generate Alice's Keypair for ultimately signing and setting as the source
alice_seed = 'SAZJ3EDATROKTNNN4WZBZPRC34AN5WR43VEHAFKT5D66UEZTKDNKUHOK'
alice_kp = Keypair.from_seed(alice_seed)
# Bob's address, for the destination
bob_address = 'GDLP3SP4WP72L4BAJWZUDZ6SAYE4NAWILT5WQDS7RWC4XCUNUQDRB2A4'
# The CNY Issuer's address
CNY_ISSUER = 'GDVDKQFP665JAO7A2LSHNLQIUNYNAAIGJ6FYJVMG4DT3YJQQJSRBLQDG'
horizon = horizon_testnet()
# horizon = horizon_livenet() for LIVENET
# create op
amount = '100'
asset = Asset('CNY', CNY_ISSUER)
op = Payment(
# Source is also inferred from the transaction source, so it's optional.
source=alice_kp.address().decode(),
destination=bob_address,
asset=asset,
amount=amount
)
# create a memo
msg = TextMemo('For beers yesterday!')
# Get the current sequence of Alice
# Python 3
sequence = horizon.account(alice_kp.address().decode('utf-8')).get('sequence')
# Python 2
# sequence = horizon.account(alice_kp.address()).get('sequence')
# Construct a transaction
tx = Transaction(
source=alice_kp.address().decode(),
sequence=sequence,
# time_bounds = {'minTime': 1531000000, 'maxTime': 1531234600},
memo=msg,
fee=100, # Can specify a fee or use the default by not specifying it
operations=[
op,
],
)
# Build transaction envelope
envelope = Te(tx=tx, network_id="TESTNET") # or 'PUBLIC'
# Sign the envelope
envelope.sign(alice_kp)
# Submit the transaction to Horizon!
xdr = envelope.xdr()
response = horizon.submit(xdr)
What's Next
===========
From here, we recommend you explore our :ref:`api`. In there you'll find out
more about the various objects that represent concepts in Stellar, as well as
some of the additional helper classes and functions that exist.
Happy Coding!