In this post I am going to discuss how to create a decentralized blockchain app aka dApp for Stellar Network. I will build a very simple web app, world’s simplest Ecommerce app, called it RocketCommerce where people can buy a single item by paying Lumens(XLM), stellar’s currency. The interface of the app looks like below:

Before we get into the development of the application itself, allow me to discuss some background of Blockchain, decentralized apps and Stellar Network itself.

What is Blockchain?

From Wikipedia: A blockchain, originally block chain is a continuously growing list of records, called blocks, which are linked and secured using cryptography.[1][6] Each block typically contains a cryptographic hash of the previous block,[6] a timestamp and transaction data.[7] By design, a blockchain is inherently resistant to modification of the data. It is “an open, distributed ledger that can record transactions between two parties efficiently and in a verifiable and permanent way

Don Tapscott says:

The blockchain is an incorruptible digital ledger of economic transactions that can be programmed to record not just financial transactions but virtually everything of value

What is a decentralized App or dApp?

In simple words dApps are the apps that run on P2P networks instead of running from a single server, entity or organization. P2P Apps are not new, remember Napster and torrents? they are early adaption of decentralized networks.

What is a Stellar Network?

In short Stellar network is a certain P2P network that is based on blockchain technology that performs operations very fast. Like many other coins it’s code is also open source and available on Github. You can learn further about it’s working here. Also there’s a separate section only for developers which you can access here. SDKs are available for different languages but since this post is about Python so we will focus on Python SDK only. I am going to make a simple web app in Python Flask that will interact with Stellar SDK for transactions and other operations.

The app is very simple and might not be taking care of a professional workflow but that’s OK; The app will be maintaining the wallets of all members thus the respective private keys. We first will be creating Wallet addresses and performed action on it. One of the address of the Business Wallet that will be receiving payments and other by the customer, which also be maintained by the site itself (nothing unique as sites like Earn.com maintains wallets of their users and dispatch money in it). It’s also assumed that the users are registered and their wallets generated at the time of signup. We will discuss how addresses are generated for Stellar network. We will be using TestNet instead of PubNet for this app. TestNets are similar to PubNet or Public Networks, just that they are using for testing and development purpose and issue fake tokens for transactions. We will be using Stellar Horizon Server having address:- http://horizon-testnet.stellar.org

OK enough talk, let’s get into the development!

What is Stellar Horizon Server?

From Stellar’s Official Site:

Horizon is an API server for the Stellar ecosystem. It acts as the interface between stellar-core and applications that want to access the Stellar network. It allows you to submit transactions to the network, check the status of accounts, subscribe to event streams, etc.

Basically, Horizon is kind of an API based front-end for the core Stellar System that let you interact with the main network by using APIs. I find it very helpful; unlike Ethereum where you have to learn a new language(Solidity) to write apps aka Smart Contracts, the learning curve is very small and you can consume APIs in your favorite language. We will not be interacting with Horizon APIs directly as we are going to use Python SDK that are wrappers of the APIs itself and hide many unnecessary things that could become obstacles for beginners.

Python SDK Installation

We will be installing Python SDk via pip utility:

pip install stellar-base

It will install the main SDK along with all dependencies. I have been on Python3 for long time, not sure it will work for Py2 or not, give it a try. Most important give Python3 a try!

Setting up Wallets

The very first thing we need to do is to generate at least a couple of wallets here; one for the company receiving payments and other for the customer. This post is using Flask for writing app so It’s assumed you know Flask well, if not, you may find some good tutorial out there.

from flask import Flask, redirect from flask import render_template, request from stellar_base.keypair import Keypair import json @app.route("/gen_address") def gen_address(): kp = Keypair.random() publickey = kp.address().decode() seed = kp.seed().decode() return json.dumps({'publickey': publickey, 'seed': seed}) 1 2 3 4 5 6 7 8 9 10 11 from flask import Flask , redirect from flask import render_template , request from stellar_base . keypair import Keypair import json @ app . route ( "/gen_address" ) def gen_address ( ) : kp = Keypair . random ( ) publickey = kp . address ( ) . decode ( ) seed = kp . seed ( ) . decode ( ) return json . dumps ( { 'publickey' : publickey , 'seed' : seed } )

After importing Flask related stuff, I imported Stellar’s Keypair class. It will be responsible to generate a new wallet address and a private key aka seed that will be a private identification or password for the wallet itself. You keep this thing secure somewhere and provide a public key aka Wallet address to others for transaction purpose. Since we want to return both private and public keys aka Wallet Addresses, I will convert dict into a json and return.

Start the flask server by running python app.py from command line. It shows something like below:

1 2 3 * Running on http : //127.0.0.1:5000/ (Press CTRL+C to quit) * Restarting with stat * Debugger is active !

Once it’s running you should access http://127.0.0.1:5000/gen_address to generate the address. If all goes well it will generate output like below:

{ "seed": "SABA7LBKQOIWZENE7TU442ZLJM7HAPRKTFBSM656UONB2UMCVB3MDK24", "publickey": "GA36WRQJSJIKTAKD2MJNVGUXUGLBAXEKKXIQENRNU3J5PNEZLCCD3M5L" } 1 2 3 4 { "seed" : "SABA7LBKQOIWZENE7TU442ZLJM7HAPRKTFBSM656UONB2UMCVB3MDK24" , "publickey" : "GA36WRQJSJIKTAKD2MJNVGUXUGLBAXEKKXIQENRNU3J5PNEZLCCD3M5L" }

Let’s run it one more time to generate another address and this time it produces:

{ "seed": "SBGUJJV6FSUL5S3AWH36XPYFIGGMAV3RQK7NSZWO7PTIS2ZCSPFVREGT", "publickey": "GBYVSIXRDKJDHY5JGK6N37RFLZ2JDH3GDZPYOWXITQCWOCQ26VSRSXZF" } 1 2 3 4 { "seed" : "SBGUJJV6FSUL5S3AWH36XPYFIGGMAV3RQK7NSZWO7PTIS2ZCSPFVREGT" , "publickey" : "GBYVSIXRDKJDHY5JGK6N37RFLZ2JDH3GDZPYOWXITQCWOCQ26VSRSXZF" }

In the __main__ of your Flask app assign these addresses to some variables, I do as below:

SITE_ADDR = 'GAFNKWN2GX7FCCSYLS36OUN2NIWJAU4UVZC44MVTQQX6HDAUZ2UUQL6I' SITE_SEED = 'SCC2V25EPMDLWUXNOJNLTBFXMWDHLLNJOY4DN5LWIEKFMYADNPW2OFXX' 1 2 SITE_ADDR = 'GAFNKWN2GX7FCCSYLS36OUN2NIWJAU4UVZC44MVTQQX6HDAUZ2UUQL6I' SITE_SEED = 'SCC2V25EPMDLWUXNOJNLTBFXMWDHLLNJOY4DN5LWIEKFMYADNPW2OFXX'

and for the customer:

MEMBER_ADD = 'GBYVSIXRDKJDHY5JGK6N37RFLZ2JDH3GDZPYOWXITQCWOCQ26VSRSXZF' MEMBER_SEED = 'SBGUJJV6FSUL5S3AWH36XPYFIGGMAV3RQK7NSZWO7PTIS2ZCSPFVREGT' 1 2 MEMBER_ADD = 'GBYVSIXRDKJDHY5JGK6N37RFLZ2JDH3GDZPYOWXITQCWOCQ26VSRSXZF' MEMBER_SEED = 'SBGUJJV6FSUL5S3AWH36XPYFIGGMAV3RQK7NSZWO7PTIS2ZCSPFVREGT'

Notice G in Stellar wallet’s address and S in seed values. This is standard by Stellar.

The Flask app’s __main__ will look like below:

if __name__ == "__main__": SITE_ADDR = 'GAFNKWN2GX7FCCSYLS36OUN2NIWJAU4UVZC44MVTQQX6HDAUZ2UUQL6I' SITE_SEED = 'SCC2V25EPMDLWUXNOJNLTBFXMWDHLLNJOY4DN5LWIEKFMYADNPW2OFXX' MEMBER_ADD = 'GBYVSIXRDKJDHY5JGK6N37RFLZ2JDH3GDZPYOWXITQCWOCQ26VSRSXZF' MEMBER_SEED = 'SBGUJJV6FSUL5S3AWH36XPYFIGGMAV3RQK7NSZWO7PTIS2ZCSPFVREGT' app.run(debug=True) 1 2 3 4 5 6 7 if __name__ == "__main__" : SITE_ADDR = 'GAFNKWN2GX7FCCSYLS36OUN2NIWJAU4UVZC44MVTQQX6HDAUZ2UUQL6I' SITE_SEED = 'SCC2V25EPMDLWUXNOJNLTBFXMWDHLLNJOY4DN5LWIEKFMYADNPW2OFXX' MEMBER_ADD = 'GBYVSIXRDKJDHY5JGK6N37RFLZ2JDH3GDZPYOWXITQCWOCQ26VSRSXZF' MEMBER_SEED = 'SBGUJJV6FSUL5S3AWH36XPYFIGGMAV3RQK7NSZWO7PTIS2ZCSPFVREGT' app . run ( debug = True )

So far so good. Addresses are generated but hold on! you still can’t use them. The reason is that these wallet are empty and yet not registered with the main TestNet. You need some money to buy, right? So who will pay, well, a FriendBot in need is a friend indeed. Stellar provides a friend bot. What this bot does that it hands you over 1000 coins for shopping (Wish they have a friend bot or a friend for main network too! Stellar team! please do something, pretty please??). So you gotta make a request to fetch some XLMs first. Let’s first access main Horizon Server. When you go to:- https://horizon-testnet.stellar.org/ it provides following output:

{ "_links": { "account": { "href": "https://horizon-testnet.stellar.org/accounts/{account_id}", "templated": true }, "account_transactions": { "href": "https://horizon-testnet.stellar.org/accounts/{account_id}/transactions{?cursor,limit,order}", "templated": true }, "assets": { "href": "https://horizon-testnet.stellar.org/assets{?asset_code,asset_issuer,cursor,limit,order}", "templated": true }, "friendbot": { "href": "https://horizon-testnet.stellar.org/friendbot{?addr}", "templated": true }, "metrics": { "href": "https://horizon-testnet.stellar.org/metrics" }, "order_book": { "href": "https://horizon-testnet.stellar.org/order_book{?selling_asset_type,selling_asset_code,selling_issuer,buying_asset_type,buying_asset_code,buying_issuer,limit}", "templated": true }, "self": { "href": "https://horizon-testnet.stellar.org/" }, "transaction": { "href": "https://horizon-testnet.stellar.org/transactions/{hash}", "templated": true }, "transactions": { "href": "https://horizon-testnet.stellar.org/transactions{?cursor,limit,order}", "templated": true } }, "horizon_version": "snapshot-snapshots-3-gbc25555", "core_version": "v9.1.0", "history_latest_ledger": 7319835, "history_elder_ledger": 1, "core_latest_ledger": 7319835, "network_passphrase": "Test SDF Network ; September 2015", "protocol_version": 9 } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 { "_links" : { "account" : { "href" : "https://horizon-testnet.stellar.org/accounts/{account_id}" , "templated" : true } , "account_transactions" : { "href" : "https://horizon-testnet.stellar.org/accounts/{account_id}/transactions{?cursor,limit,order}" , "templated" : true } , "assets" : { "href" : "https://horizon-testnet.stellar.org/assets{?asset_code,asset_issuer,cursor,limit,order}" , "templated" : true } , "friendbot" : { "href" : "https://horizon-testnet.stellar.org/friendbot{?addr}" , "templated" : true } , "metrics" : { "href" : "https://horizon-testnet.stellar.org/metrics" } , "order_book" : { "href" : "https://horizon-testnet.stellar.org/order_book{?selling_asset_type,selling_asset_code,selling_issuer,buying_asset_type,buying_asset_code,buying_issuer,limit}" , "templated" : true } , "self" : { "href" : "https://horizon-testnet.stellar.org/" } , "transaction" : { "href" : "https://horizon-testnet.stellar.org/transactions/{hash}" , "templated" : true } , "transactions" : { "href" : "https://horizon-testnet.stellar.org/transactions{?cursor,limit,order}" , "templated" : true } } , "horizon_version" : "snapshot-snapshots-3-gbc25555" , "core_version" : "v9.1.0" , "history_latest_ledger" : 7319835 , "history_elder_ledger" : 1 , "core_latest_ledger" : 7319835 , "network_passphrase" : "Test SDF Network ; September 2015" , "protocol_version" : 9 }

As you can see it provides different end points here. What I am going to access is: https://horizon-testnet.stellar.org/accounts/{account_id} by setting the address so it will then become https://horizon-testnet.stellar.org/accounts/GBYVSIXRDKJDHY5JGK6N37RFLZ2JDH3GDZPYOWXITQCWOCQ26VSRSXZF . If you check the JSON output it looks like below:

{ "type": "https://stellar.org/horizon-errors/not_found", "title": "Resource Missing", "status": 404, "detail": "The resource at the url requested was not found. This is usually occurs for one of two reasons: The url requested is not valid, or no data in our database could be found with the parameters provided.", "instance": "horizon-testnet-001/6VNfUsVQkZ-34435203" } 1 2 3 4 5 6 7 { "type" : "https://stellar.org/horizon-errors/not_found" , "title" : "Resource Missing" , "status" : 404 , "detail" : "The resource at the url requested was not found. This is usually occurs for one of two reasons: The url requested is not valid, or no data in our database could be found with the parameters provided." , "instance" : "horizon-testnet-001/6VNfUsVQkZ-34435203" }

The address you generated does not exist in Stellar network. It’s time to call your friend ask for help. Go to the URL:- https://horizon-testnet.stellar.org/friendbot?addr=GBYVSIXRDKJDHY5JGK6N37RFLZ2JDH3GDZPYOWXITQCWOCQ26VSRSXZF and your friend will give you some bucks. When you access it provides following transaction output:

{ "_links": { "transaction": { "href": "https://horizon-testnet.stellar.org/transactions/17cf9104b7ac9461e19a5896556bc48f1db4c871fee783f68d100fce2e086313" } }, "hash": "17cf9104b7ac9461e19a5896556bc48f1db4c871fee783f68d100fce2e086313", "ledger": 7319955, "envelope_xdr": "AAAAABB90WssODNIgi6BHveqzxTRmIpvAFRyVNM+Hm2GVuCcAAAAZABiwhcAAF9zAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAN+tGCZJQqYFD0xLampehlhBcilXRAjYtptPXtJlYhD0AAAAXSHboAAAAAAAAAAABhlbgnAAAAEB2T1sgHCMP6f1W7FfUKz8RisZ9jqmvvw+Vn++vjk4tsPyVWzFFZr5eyA0nX4zd6SdNiYYpAJx1sCygOkDtwyEC", "result_xdr": "AAAAAAAAAGQAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAA=", "result_meta_xdr": "AAAAAAAAAAEAAAADAAAAAABvsZMAAAAAAAAAADfrRgmSUKmBQ9MS2pqXoZYQXIpV0QI2LabT17SZWIQ9AAAAF0h26AAAb7GTAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAwBvsZMAAAAAAAAAABB90WssODNIgi6BHveqzxTRmIpvAFRyVNM+Hm2GVuCcAAGO0zeHD3QAYsIXAABfcwAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAQBvsZMAAAAAAAAAABB90WssODNIgi6BHveqzxTRmIpvAFRyVNM+Hm2GVuCcAAGOu+8QJ3QAYsIXAABfcwAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAA" } 1 2 3 4 5 6 7 8 9 10 11 12 { "_links" : { "transaction" : { "href" : "https://horizon-testnet.stellar.org/transactions/17cf9104b7ac9461e19a5896556bc48f1db4c871fee783f68d100fce2e086313" } } , "hash" : "17cf9104b7ac9461e19a5896556bc48f1db4c871fee783f68d100fce2e086313" , "ledger" : 7319955 , "envelope_xdr" : "AAAAABB90WssODNIgi6BHveqzxTRmIpvAFRyVNM+Hm2GVuCcAAAAZABiwhcAAF9zAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAN+tGCZJQqYFD0xLampehlhBcilXRAjYtptPXtJlYhD0AAAAXSHboAAAAAAAAAAABhlbgnAAAAEB2T1sgHCMP6f1W7FfUKz8RisZ9jqmvvw+Vn++vjk4tsPyVWzFFZr5eyA0nX4zd6SdNiYYpAJx1sCygOkDtwyEC" , "result_xdr" : "AAAAAAAAAGQAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAA=" , "result_meta_xdr" : "AAAAAAAAAAEAAAADAAAAAABvsZMAAAAAAAAAADfrRgmSUKmBQ9MS2pqXoZYQXIpV0QI2LabT17SZWIQ9AAAAF0h26AAAb7GTAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAwBvsZMAAAAAAAAAABB90WssODNIgi6BHveqzxTRmIpvAFRyVNM+Hm2GVuCcAAGO0zeHD3QAYsIXAABfcwAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAQBvsZMAAAAAAAAAABB90WssODNIgi6BHveqzxTRmIpvAFRyVNM+Hm2GVuCcAAGOu+8QJ3QAYsIXAABfcwAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAA" }

you can see transaction field with the URL. It’s standard by Stellar that gives you hint that is, All goes well. The transaction link you get something different. Most important part for us is:

"balances": [ { "balance": "10000.0000000", "asset_type": "native" } ] 1 2 3 4 5 6 "balances" : [ { "balance" : "10000.0000000" , "asset_type" : "native" } ]

Yay!! the friend rocks! he gave me 1000 XLM free!!

Alright enough excitement, it’s time to do shopping. But! before that we need to write the method that will be taking care of transaction.

def send_payment(amount, item, asset='XLM'): flag = False try: builder = Builder(secret=MEMBER_SEED) builder.append_payment_op(SITE_ADDR, amount, asset) builder.add_text_memo(item) builder.sign() s = builder.submit() print(s['_links']) flag = True except Exception as ex: print('Error in Payment') print(str(ex)) finally: return flag 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 def send_payment ( amount , item , asset = 'XLM' ) : flag = False try : builder = Builder ( secret = MEMBER_SEED ) builder . append_payment_op ( SITE_ADDR , amount , asset ) builder . add_text_memo ( item ) builder . sign ( ) s = builder . submit ( ) print ( s [ '_links' ] ) flag = True except Exception as ex : print ( 'Error in Payment' ) print ( str ( ex ) ) finally : return flag

I am calling a Builder class that will be building up the payment object. The Builder class take seed as a parameter. You need seed to make a transaction. Since RocketCommerce is maintaining customers wallets too so they are making payments on behalf of their customers.

So member seed is provided. The method append_payment_op() is used to assign the receiver’s address. In our case SITE_ADDR , the amount and the currency. In our case it’s XLM . Stellar can take care of other tokens and FIAT currency issuers as well and that’s the beauty of the Stellar that you could use both conventional and crypto coins on it. Next up you call add_text_memo with your transaction. It’s for friendly note. In my case I will be setting the customer name itself. You then sign your transaction and then submit it to the network. In our /pay route it looks like below:

@app.route("/pay", methods=['GET', 'POST']) def pay(): result = False item = 'Buyer - Jon Doe' amt = 10 result = send_payment(amt, item) if result: return redirect("/thanks", code=302) else: return 'Invalid Transaction' 1 2 3 4 5 6 7 8 9 10 11 12 @ app . route ( "/pay" , methods = [ 'GET' , 'POST' ] ) def pay ( ) : result = False item = 'Buyer - Jon Doe' amt = 10 result = send_payment ( amt , item ) if result : return redirect ( "/thanks" , code = 302 ) else : return 'Invalid Transaction'

I have kept it simple otherwise you can fetch the transaction from the returned JSON and make it more secure and sophisticated. If all goes well it redirects to to /thanks otherwise print Invalid Transaction . I am also printing the transaction url on console for debugging purpose. I am not gonna discuss how the screens were made since it’s out of the scope but screens will appear in order given below:

But wait.. it seems transaction failed as I got this object:

{ 'extras': { 'result_codes': { 'transaction': 'tx_failed', 'operations': [ 'op_malformed' ] }, 'envelope_xdr': 'AAAAAHFZIvEakjPjqTK83f4lXnSRn2YeX4da6JwFZwoa9WUZAAAAZABtEXQAAAAFAAAAAAAAAAEAAAAPQnV5ZXIgLSBKb24gRG9lAAAAAAEAAAAAAAAAAQAAAAAK1Vm6Nf5RClhct+dRumoskFOUrkXOMrOEL+OMFM6pSAAAAAAAAAAAAAAAAAAAAAAAAAABGvVlGQAAAEB4ypUfI55TnPEhCcg1OyaKQvt3Z0zhd0SpQLtpdjyQXw4l+8px7G4GX/K/xYSLxONB9yv5Bep5UBTrzQM4N3YL', 'result_xdr': 'AAAAAAAAAGT/////AAAAAQAAAAAAAAAB/////wAAAAA=' }, 'instance': 'horizon-testnet-001/6VNfUsVQkZ-34516819', 'type': 'https://stellar.org/horizon-errors/transaction_failed', 'detail': 'The transaction failed when submitted to the stellar network. The `extras.result_codes` field on this response contains further details. Descriptions of each code can be found at: https://www.stellar.org/developers/learn/concepts/list-of-operations.html', 'title': 'Transaction Failed', 'status': 400 } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 { 'extras' : { 'result_codes' : { 'transaction' : 'tx_failed' , 'operations' : [ 'op_malformed' ] } , 'envelope_xdr' : 'AAAAAHFZIvEakjPjqTK83f4lXnSRn2YeX4da6JwFZwoa9WUZAAAAZABtEXQAAAAFAAAAAAAAAAEAAAAPQnV5ZXIgLSBKb24gRG9lAAAAAAEAAAAAAAAAAQAAAAAK1Vm6Nf5RClhct+dRumoskFOUrkXOMrOEL+OMFM6pSAAAAAAAAAAAAAAAAAAAAAAAAAABGvVlGQAAAEB4ypUfI55TnPEhCcg1OyaKQvt3Z0zhd0SpQLtpdjyQXw4l+8px7G4GX/K/xYSLxONB9yv5Bep5UBTrzQM4N3YL' , 'result_xdr' : 'AAAAAAAAAGT/////AAAAAQAAAAAAAAAB/////wAAAAA=' } , 'instance' : 'horizon-testnet-001/6VNfUsVQkZ-34516819' , 'type' : 'https://stellar.org/horizon-errors/transaction_failed' , 'detail' : 'The transaction failed when submitted to the stellar network. The `extras.result_codes` field on this response contains further details. Descriptions of each code can be found at: https://www.stellar.org/developers/learn/concepts/list-of-operations.html' , 'title' : 'Transaction Failed' , 'status' : 400 }

How do I check it out? Well Stellar has provided us a tool called XDR Viewer (Thanks @mikefair to come up with XDR debugging point and then @sacarlson on Stellar Slack channel to help me out to find this issue with help of XDR Viewer) which you can read the content of envolope_xdr and figure out the reason. I input my XDR value and it produce the output. Do you see amount: 0 (raw: 0 ) there? it seems I am passing the 0 value to it that is I want to buy and paying nothing! Fix it up and it should work. I fixed it up and this time I got this encouraging JSON output

{ '_links': { 'transaction': { 'href': 'https://horizon-testnet.stellar.org/transactions/5ce05fadbe55db8f4bfd7fd33896827ceff41bc099273be06a6545aec535a4c7' } }, 'ledger': 7321632, 'envelope_xdr': 'AAAAAHFZIvEakjPjqTK83f4lXnSRn2YeX4da6JwFZwoa9WUZAAAAZABtEXQAAAAEAAAAAAAAAAEAAAAPQnV5ZXIgLSBKb24gRG9lAAAAAAEAAAAAAAAAAQAAAAAK1Vm6Nf5RClhct+dRumoskFOUrkXOMrOEL+OMFM6pSAAAAAAAAAAABfXhAAAAAAAAAAABGvVlGQAAAEBTdCVEsGl2zsR8sTyXM0NWJw4k+alHdgoVE3KY2L1CdMMkdlaLoRdRBcOz68fr5K/Y4PZHqind4GTmTaCjl7UK', 'hash': '5ce05fadbe55db8f4bfd7fd33896827ceff41bc099273be06a6545aec535a4c7', 'result_xdr': 'AAAAAAAAAGQAAAAAAAAAAQAAAAAAAAABAAAAAAAAAAA=', 'result_meta_xdr': 'AAAAAAAAAAEAAAAEAAAAAwBvt94AAAAAAAAAAArVWbo1/lEKWFy351G6aiyQU5SuRc4ys4Qv44wUzqlIAAAAFyXkyrQAaSDoAAAACwAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAQBvuCAAAAAAAAAAAArVWbo1/lEKWFy351G6aiyQU5SuRc4ys4Qv44wUzqlIAAAAFyvaq7QAaSDoAAAACwAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAwBvuCAAAAAAAAAAAHFZIvEakjPjqTK83f4lXnSRn2YeX4da6JwFZwoa9WUZAAAAF2sI/3AAbRF0AAAABAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAQBvuCAAAAAAAAAAAHFZIvEakjPjqTK83f4lXnSRn2YeX4da6JwFZwoa9WUZAAAAF2UTHnAAbRF0AAAABAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAA' } 1 2 3 4 5 6 7 8 9 10 11 12 { '_links' : { 'transaction' : { 'href' : 'https://horizon-testnet.stellar.org/transactions/5ce05fadbe55db8f4bfd7fd33896827ceff41bc099273be06a6545aec535a4c7' } } , 'ledger' : 7321632 , 'envelope_xdr' : 'AAAAAHFZIvEakjPjqTK83f4lXnSRn2YeX4da6JwFZwoa9WUZAAAAZABtEXQAAAAEAAAAAAAAAAEAAAAPQnV5ZXIgLSBKb24gRG9lAAAAAAEAAAAAAAAAAQAAAAAK1Vm6Nf5RClhct+dRumoskFOUrkXOMrOEL+OMFM6pSAAAAAAAAAAABfXhAAAAAAAAAAABGvVlGQAAAEBTdCVEsGl2zsR8sTyXM0NWJw4k+alHdgoVE3KY2L1CdMMkdlaLoRdRBcOz68fr5K/Y4PZHqind4GTmTaCjl7UK' , 'hash' : '5ce05fadbe55db8f4bfd7fd33896827ceff41bc099273be06a6545aec535a4c7' , 'result_xdr' : 'AAAAAAAAAGQAAAAAAAAAAQAAAAAAAAABAAAAAAAAAAA=' , 'result_meta_xdr' : 'AAAAAAAAAAEAAAAEAAAAAwBvt94AAAAAAAAAAArVWbo1/lEKWFy351G6aiyQU5SuRc4ys4Qv44wUzqlIAAAAFyXkyrQAaSDoAAAACwAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAQBvuCAAAAAAAAAAAArVWbo1/lEKWFy351G6aiyQU5SuRc4ys4Qv44wUzqlIAAAAFyvaq7QAaSDoAAAACwAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAwBvuCAAAAAAAAAAAHFZIvEakjPjqTK83f4lXnSRn2YeX4da6JwFZwoa9WUZAAAAF2sI/3AAbRF0AAAABAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAQBvuCAAAAAAAAAAAHFZIvEakjPjqTK83f4lXnSRn2YeX4da6JwFZwoa9WUZAAAAF2UTHnAAbRF0AAAABAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAA' }

If you notice, transaction field is same as we had when our friend paid us. Let’s check the transaction URL. It returns a big JSON output, I am pasting relevant chunk below:

{ 'hash': '0db911a502ddd67164a70c0c0627614d0619f3d9d1cac58d45ea3c7b23a0fedf', 'result_xdr': 'AAAAAAAAAGQAAAAAAAAAAQAAAAAAAAABAAAAAAAAAAA=', 'ledger': 7322697, 'envelope_xdr': 'AAAAAHFZIvEakjPjqTK83f4lXnSRn2YeX4da6JwFZwoa9WUZAAAAZABtEXQAAAAJAAAAAAAAAAEAAAAPQnV5ZXIgLSBKb24gRG9lAAAAAAEAAAAAAAAAAQAAAAAK1Vm6Nf5RClhct+dRumoskFOUrkXOMrOEL+OMFM6pSAAAAAAAAAAABfXhAAAAAAAAAAABGvVlGQAAAEDK/dXv9kt8i2phJtjuazL7OEwjDQSkjdS6QOWjLYCjozu82wggag5CnzdUN2MpPp2Hony7y3SL8flkp7ggA3EJ', '_links': { 'transaction': { 'href': 'https://horizon-testnet.stellar.org/transactions/0db911a502ddd67164a70c0c0627614d0619f3d9d1cac58d45ea3c7b23a0fedf' } }, 'result_meta_xdr': 'AAAAAAAAAAEAAAAEAAAAAwBvuZMAAAAAAAAAAArVWbo1/lEKWFy351G6aiyQU5SuRc4ys4Qv44wUzqlIAAAAF50aXrQAaSDoAAAACwAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAQBvvEkAAAAAAAAAAArVWbo1/lEKWFy351G6aiyQU5SuRc4ys4Qv44wUzqlIAAAAF6MQP7QAaSDoAAAACwAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAwBvvEkAAAAAAAAAAHFZIvEakjPjqTK83f4lXnSRn2YeX4da6JwFZwoa9WUZAAAAFvPTaXwAbRF0AAAACQAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAQBvvEkAAAAAAAAAAHFZIvEakjPjqTK83f4lXnSRn2YeX4da6JwFZwoa9WUZAAAAFu3diHwAbRF0AAAACQAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAA' } 1 2 3 4 5 6 7 8 9 10 11 12 { 'hash' : '0db911a502ddd67164a70c0c0627614d0619f3d9d1cac58d45ea3c7b23a0fedf' , 'result_xdr' : 'AAAAAAAAAGQAAAAAAAAAAQAAAAAAAAABAAAAAAAAAAA=' , 'ledger' : 7322697 , 'envelope_xdr' : 'AAAAAHFZIvEakjPjqTK83f4lXnSRn2YeX4da6JwFZwoa9WUZAAAAZABtEXQAAAAJAAAAAAAAAAEAAAAPQnV5ZXIgLSBKb24gRG9lAAAAAAEAAAAAAAAAAQAAAAAK1Vm6Nf5RClhct+dRumoskFOUrkXOMrOEL+OMFM6pSAAAAAAAAAAABfXhAAAAAAAAAAABGvVlGQAAAEDK/dXv9kt8i2phJtjuazL7OEwjDQSkjdS6QOWjLYCjozu82wggag5CnzdUN2MpPp2Hony7y3SL8flkp7ggA3EJ' , '_links' : { 'transaction' : { 'href' : 'https://horizon-testnet.stellar.org/transactions/0db911a502ddd67164a70c0c0627614d0619f3d9d1cac58d45ea3c7b23a0fedf' } } , 'result_meta_xdr' : 'AAAAAAAAAAEAAAAEAAAAAwBvuZMAAAAAAAAAAArVWbo1/lEKWFy351G6aiyQU5SuRc4ys4Qv44wUzqlIAAAAF50aXrQAaSDoAAAACwAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAQBvvEkAAAAAAAAAAArVWbo1/lEKWFy351G6aiyQU5SuRc4ys4Qv44wUzqlIAAAAF6MQP7QAaSDoAAAACwAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAwBvvEkAAAAAAAAAAHFZIvEakjPjqTK83f4lXnSRn2YeX4da6JwFZwoa9WUZAAAAFvPTaXwAbRF0AAAACQAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAQBvvEkAAAAAAAAAAHFZIvEakjPjqTK83f4lXnSRn2YeX4da6JwFZwoa9WUZAAAAFu3diHwAbRF0AAAACQAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAA' }

This output is enough for you to learn that transaction is successful as in successful one you get a transaction url, in this case it is https://horizon-testnet.stellar.org/transactions/0db911a502ddd67164a70c0c0627614d0619f3d9d1cac58d45ea3c7b23a0fedf but if you are still restless and want to know more about it then access the URL and another JSON will welcome you, the relevant chunk is below:

"id": "0db911a502ddd67164a70c0c0627614d0619f3d9d1cac58d45ea3c7b23a0fedf", "paging_token": "31450744133521408", "hash": "0db911a502ddd67164a70c0c0627614d0619f3d9d1cac58d45ea3c7b23a0fedf", "ledger": 7322697, "created_at": "2018-02-13T08:50:34Z", "source_account": "GBYVSIXRDKJDHY5JGK6N37RFLZ2JDH3GDZPYOWXITQCWOCQ26VSRSXZF", "source_account_sequence": "30699962375340041", "fee_paid": 100, "operation_count": 1, "envelope_xdr": "AAAAAHFZIvEakjPjqTK83f4lXnSRn2YeX4da6JwFZwoa9WUZAAAAZABtEXQAAAAJAAAAAAAAAAEAAAAPQnV5ZXIgLSBKb24gRG9lAAAAAAEAAAAAAAAAAQAAAAAK1Vm6Nf5RClhct+dRumoskFOUrkXOMrOEL+OMFM6pSAAAAAAAAAAABfXhAAAAAAAAAAABGvVlGQAAAEDK/dXv9kt8i2phJtjuazL7OEwjDQSkjdS6QOWjLYCjozu82wggag5CnzdUN2MpPp2Hony7y3SL8flkp7ggA3EJ", "result_xdr": "AAAAAAAAAGQAAAAAAAAAAQAAAAAAAAABAAAAAAAAAAA=", "result_meta_xdr": "AAAAAAAAAAEAAAAEAAAAAwBvuZMAAAAAAAAAAArVWbo1/lEKWFy351G6aiyQU5SuRc4ys4Qv44wUzqlIAAAAF50aXrQAaSDoAAAACwAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAQBvvEkAAAAAAAAAAArVWbo1/lEKWFy351G6aiyQU5SuRc4ys4Qv44wUzqlIAAAAF6MQP7QAaSDoAAAACwAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAwBvvEkAAAAAAAAAAHFZIvEakjPjqTK83f4lXnSRn2YeX4da6JwFZwoa9WUZAAAAFvPTaXwAbRF0AAAACQAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAQBvvEkAAAAAAAAAAHFZIvEakjPjqTK83f4lXnSRn2YeX4da6JwFZwoa9WUZAAAAFu3diHwAbRF0AAAACQAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAA", "fee_meta_xdr": "AAAAAgAAAAMAb7mTAAAAAAAAAABxWSLxGpIz46kyvN3+JV50kZ9mHl+HWuicBWcKGvVlGQAAABbz02ngAG0RdAAAAAgAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAEAb7xJAAAAAAAAAABxWSLxGpIz46kyvN3+JV50kZ9mHl+HWuicBWcKGvVlGQAAABbz02l8AG0RdAAAAAkAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAA==", "memo_type": "text", "memo": "Buyer - Jon Doe", 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 "id" : "0db911a502ddd67164a70c0c0627614d0619f3d9d1cac58d45ea3c7b23a0fedf" , "paging_token" : "31450744133521408" , "hash" : "0db911a502ddd67164a70c0c0627614d0619f3d9d1cac58d45ea3c7b23a0fedf" , "ledger" : 7322697 , "created_at" : "2018-02-13T08:50:34Z" , "source_account" : "GBYVSIXRDKJDHY5JGK6N37RFLZ2JDH3GDZPYOWXITQCWOCQ26VSRSXZF" , "source_account_sequence" : "30699962375340041" , "fee_paid" : 100 , "operation_count" : 1 , "envelope_xdr" : "AAAAAHFZIvEakjPjqTK83f4lXnSRn2YeX4da6JwFZwoa9WUZAAAAZABtEXQAAAAJAAAAAAAAAAEAAAAPQnV5ZXIgLSBKb24gRG9lAAAAAAEAAAAAAAAAAQAAAAAK1Vm6Nf5RClhct+dRumoskFOUrkXOMrOEL+OMFM6pSAAAAAAAAAAABfXhAAAAAAAAAAABGvVlGQAAAEDK/dXv9kt8i2phJtjuazL7OEwjDQSkjdS6QOWjLYCjozu82wggag5CnzdUN2MpPp2Hony7y3SL8flkp7ggA3EJ" , "result_xdr" : "AAAAAAAAAGQAAAAAAAAAAQAAAAAAAAABAAAAAAAAAAA=" , "result_meta_xdr" : "AAAAAAAAAAEAAAAEAAAAAwBvuZMAAAAAAAAAAArVWbo1/lEKWFy351G6aiyQU5SuRc4ys4Qv44wUzqlIAAAAF50aXrQAaSDoAAAACwAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAQBvvEkAAAAAAAAAAArVWbo1/lEKWFy351G6aiyQU5SuRc4ys4Qv44wUzqlIAAAAF6MQP7QAaSDoAAAACwAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAwBvvEkAAAAAAAAAAHFZIvEakjPjqTK83f4lXnSRn2YeX4da6JwFZwoa9WUZAAAAFvPTaXwAbRF0AAAACQAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAQBvvEkAAAAAAAAAAHFZIvEakjPjqTK83f4lXnSRn2YeX4da6JwFZwoa9WUZAAAAFu3diHwAbRF0AAAACQAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAA" , "fee_meta_xdr" : "AAAAAgAAAAMAb7mTAAAAAAAAAABxWSLxGpIz46kyvN3+JV50kZ9mHl+HWuicBWcKGvVlGQAAABbz02ngAG0RdAAAAAgAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAEAb7xJAAAAAAAAAABxWSLxGpIz46kyvN3+JV50kZ9mHl+HWuicBWcKGvVlGQAAABbz02l8AG0RdAAAAAkAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAA==" , "memo_type" : "text" , "memo" : "Buyer - Jon Doe" ,

fee_paid tells the fee Stellar network charges, source_account is account sent money. memo tells the customer name you had set. If you notice you don’t find the amount field here. For that you gotta check envelope_xdr content in XDRViewer. Here you can see amount: 10 (raw: 100000000 ) mentioned that tells how much amount was sent. Check the member account again by accessing the account URL, check the balance now, it’s reduced now:

"balances": [ { "balance": "9847.9999100", "asset_type": "native" } ], 1 2 3 4 5 6 "balances" : [ { "balance" : "9847.9999100" , "asset_type" : "native" } ] ,

Conclusion

That’s it! in this post you learnt how easy it is to start writing blockchain apps for Stellar network and if you know Python it makes your learning curve further small. One might ask why did I pick Stellar, the answer is simple: I like this project and being both developer and an Stellar Lumens investor I found it very interesting and good project. The community is very helpful, documentation is very awesome and it did not take much time to write a simple app running on their network.

The code is available on Github

If you like this post or have some feedback then do comment below. Specially from Stellar experts so that in case if I did something wrong then I could correct it.

Oh and if you liked it so much and want to become a human version of a FriendBot for me then you can send XLM to me on the following address:

Address:- GB6YPGW5JFMMP2QB2USQ33EUWTXVL4ZT5ITUNCY3YKVWOJPP57CANOF3

Memo:- 8b54d016b8db47cda46

And since I am on Bittrex it provides some instructions as well

Stellar provides some instructions as well.

Or just plain BTC:- 12stJs8vZNuuVfjZSSzpLPA96quNissk1b 🙂





