Exploring Stellar Lumens — Development Tutorial
Today, I got the opportunity to explore the technical side of Stellar Lumens and make an analysis of the pros/cons. I guess I can finally cross that off my bucket list! The goal of this article is to push a simple transaction to the Stellar network. As I couldn’t find much technical ‘how-to’ information on Stellar, I decided to do it the old way: RTFM!
Understanding Stellar
It would be nuts to immediately dive into the code, therefore I found this high-level architectural overview guide on the Stellar website.
API: Horizon
All interactions with the Stellar network happen through Horizon, a RESTful HTTP API server. It allows developers to submit transactions, check account’s balance, and subscribe to events. You can use Horizon through your web browser, a command line tool like cURL, or the Stellar SDK which is the easiest solution. The Stellar SDK is available for JavaScript, Java and Go. There are also community-maintained SDKs for Python, C#, and Ruby.
Stellar Core
The Stellar Core is the backbone of the Stellar network, every Horizon server connects with it. The Stellar Core is responsible for validating transactions and reaching consensus. The core is run by a bunch of individuals creating a decentralized network. Each transaction on the network costs a small fee: 100 stroops (equal to 0.00001 XLM). The should prevent bad entities from spamming the network.
Stellar Consensus Protocol (SCP)
SCP opts for safety over liveness — in the event of partition or misbehaving nodes, it halts the progress of the network until consensus can be reached. You can find more information on the protocol in their whitepaper.
Run Stellar Core with Docker
It is possible to become part of the network by running a Stellar Core instance. Such an instance can be easily set up with stellar/quickstart docker image.
Testnet
Luckily, Stellar provides a testnet for development purpose. Information can be found here.
Let’s code Stellar
Prerequisites: Basic knowledge of JavaScript, Express, and Async/Await.
Goal: Create two accounts on the testnet, fill the accounts with testnet tokens and transfer some random amount from one account to the other. At last, we want to be able to retrieve the transaction with the transaction explorer. In general, this Stellar coding tutorial teaches you the basics to get started with Stellar development.
Full working code: Can be found here, which makes following the tutorial easier. A complete snippet of the code is as well added at the bottom of the blog.
Create Accounts
The Stellar JavaScript SDK is the most stable SDK among the ones offered. You can easily install this package with npm: npm i -S stellar-sdk
.
We tell our Stellar SDK to use the testnet server URL:
const server = new Stellar.Server('https://horizon-testnet.stellar.org')
Stellar.Network.useTestNetwork()
We are ready to create two random accounts. The Stellar SDK offers a function to randomly create a keypair without seed.
let pairA = Stellar.Keypair.random()
let pairB = Stellar.Keypair.random()
This keypair contains a function to retrieve the public key pair.publicKey()
and secret pair.secret()
.
Next, I’ve defined a route to initialize both accounts. In this function, we will create our wallet/account based on our public key and request the stellar friendbot
to send us 10.000 testnet Lumens on both accounts. I’m using the request-promise
npm package for sending the request to the Horizon testnet API as this works well with async/await. We pass the public key from our first keypair via a query string.
await rp.get({
uri: 'https://horizon-testnet.stellar.org/friendbot',
qs: { addr: pairA.publicKey() },
json: true
})
The account is created now, but we don’t have the account object in our app. So, let’s retrieve this.
accountB = await server.loadAccount(pairB.publicKey())
It’s now possible to check whether we got some Stellar Lumens on our account.
accountA.balances.forEach((balance) => {
console.log('Type:', balance.asset_type, ', Balance:', balance.balance)
})
We repeat this code for pairB
as well in order to retrieve accountB
.
Transfer Stellar Lumens
A transaction can consist of multiple operations chained to the TransactionBuider
which creates the (multi-)transaction. To keep things simple, we will just transfer a small amount of testnet Lumens. We define the public key of pairB
as the destination. The amount transferred is equal to 30.0000001
. The StellarSDK requires the amount parameter should be stated to seven decimal places.
const transaction = new Stellar.TransactionBuilder(accountA)
.addOperation(Stellar.Operation.payment({
destination: pairB.publicKey(),
asset: Stellar.Asset.native(),
amount: '30.0000001'
}))
.build()
Cool, the transaction is ready to be signed by the initiator of the transfer — transaction.sign(pairA)
. Ok, now send this to the Horizon network: const transactionResult = await server.submitTransaction(transaction)
Retrieve History
Code below will return only one transaction per ‘history page’. You can use the next()
function on the ‘history page’ object to retrieve the next transaction in the history for an account.
let historyPage = await server.transactions()
.forAccount(accountA.accountId())
.call()
We want to print the details of the operations in the transaction (which is XDR encoded). Let’s decode to base64 and loop over the transaction’s operations to print all sent amounts.
let txDetails = Stellar.xdr.TransactionEnvelope
.fromXDR(historyPage.records[1].envelope_xdr, 'base64')txDetails._attributes.tx._attributes.operations
.map(operation => console.log(
`Transferred amount:
${operation._attributes.body._value._attributes.amount.low} XLM`
))
At last, let’s retrieve the next ‘history page’.
historyPage = await historyPage.next()
That’s it? Yes, surprised?
Did you know
- You can explore the transaction on the network — example. The link is returned in the
transactionResult
parameter:transactionResult._links.transaction.href
. - The metadata about the transaction is stored in the XDR format which is a standard data serialization format. You can deserialize it here.
- You can look up all transactions for a public key like here.
The Stellar Analysis
Pros
- Stellar is a payment engine, focused on asset movement where other blockchains may focus on the logic of the program itself. Stellar and Ripple are dealing with how your money is traded and sent, this is a more particular purpose.
- Stellar is easy to integrate for any web developer without knowing too much about blockchain.
- Perfect for payments / cross-currency / cross-border payments.
- Fast, cheap and easy to setup your own federated network: This is due to the consensus algorithm that does not use proof of work, but their custom Stellar Consensus Protocol.
- Very cheap fees: 0.00001 XLM per operation. A single transaction can contain multiple operations, so the fee doesn’t depend on the amount transferred.
Cons
- Privacy — Every transaction can be found and read with a blockchain explorer.
- Important standards missing like payments links (still in development) that slow down the adoption. Payment links would handle the click on the link prompting the user for payment which is crucial for e-commerce. For now, you need to manually copy paste address, transaction memo and amount where Bitcoin has a one-click and approve payment option.
It’s hard to determine if this is a pro/con: Stellar is not really using the concept smart contracts (it’s not Turing complete). It works for few popular use cases like escrow, time bounded and atomic transactions. However, standards can be extended for more use cases, but it will never get to the point of ‘Write your own DApp’. That’s ok as it makes Stellar optimized for this specific purpose of asset transfer, instead of being bloated by people’s fantasies.
Stellar succeeded in removing the blockchain knowledge barrier even though it’s a blockchain payment provider. — Michiel Mulders
Resources to become a Stellar expert
Full code snippet: