Blog Article

A New Go SDK for the Stellar Network

Author

Eric Saunders

Publishing date

SDK

Horizon

API

We’re pleased to announce the release of a new Go SDK for the Stellar network. Along with JavaScript and Java, this is the third official SDK supported by the Stellar Development Foundation (SDF).

horizonclient is a package that provides client access to a Stellar Horizon server. It allows you to retrieve ledger information, either as one-time calls or as a continuously updating stream. You can find account balances, check the status of a transaction, or monitor in real-time new offers for an issued token. You can also submit transactions! The client fully supports all the REST endpoints exposed by the Horizon API.


// Create a new randomly generated address
kp, err := keypair.Random()

// Create and fund the new address on TestNet, using friendbot
client := horizonclient.DefaultTestNetClient
resp, err := client.Fund(kp.Address())

// Get information about the account we just created
accountRequest := horizonclient.AccountRequest{AccountID: kp.Address()}
horizonAcct, err := client.AccountDetail(accountRequest)

A second package, txnbuild, supports the convenient construction of operations and transactions. These are the building blocks of change in the Stellar system; to make anything happen on the network requires submission of one or more operations, wrapped in a transaction.


// An operation to create a new Stellar account funded from an existing one
createAccountOp := txnbuild.CreateAccount{
	Destination: "GDKT2RF3P7VVKOCAN5UXZ2WNGRXTRWNWOCWZZWRL2WQPPROCFSE3RGRQ",
	Amount: "10",
}

// Construct the transaction that will carry the operation
tx := txnbuild.Transaction{
	SourceAccount: horizonAcct,
	Operations: []txnbuild.Operation{&createAccountOp},
	Timebounds: txnbuild.NewTimeout(300),
	Network: network.TestNetworkPassphrase,
}

Transactions built with txnbuild can be easily submitted to any Horizon server for processing via horizonclient.


// Serialise the transaction to XDR, and sign it
err := tx.Build()
err = tx.Sign(kp)

// Submit the transaction
resp, err := client.SubmitTransaction(tx)

When do you need each package? A general rule of thumb is that any action that changes the state of the Stellar ledger is built with txnbuild, while horizonclient typically retrieves information from the network. For most applications, you’ll likely need functionality from both packages.

Why a new approach?

We chose to rewrite the existing Go Horizon client because it needed significant additions, and a new structure (incorporating the best parts of the old client) was the best way to support that. For transaction building, the situation was more nuanced.

We approached this problem before with a library called build. This previous approach was very general, and undeniably elegant. But it was hard to grok. Unfortunately the relevant GoDocs are not your friend here:


func (b *CreateAccountBuilder) Mutate(muts …interface{})

This is obscure, because both specific arguments and type information are abstracted away. For a new user, this is almost impossible to understand without an example (or consulting the library source).

So we decided to take another pass at the problem.

The official JS and Java SDKs use the builder pattern. The builder pattern is particularly common in Java, because the constructor is so inflexible. Applying the pattern allows construction of the object to be decoupled from the object itself, and allows partial constructions without setting many constructors.

In Go, the pattern is less common, because i) you can do partial configuration by just setting struct fields, and ii) the pattern screws up Go’s error handling, since method chaining doesn’t play nicely with multiple return values.

The design philosophy we chose was to be efficient and minimise abstractions. We use expressive structs to make configuration as compact as possible.


// Set only the fields we're interested in
op := SetOptions{
	ClearFlags: []AccountFlag{AuthRevocable},
	SetFlags: []AccountFlag{AuthRequired, AuthImmutable},
}

All struct fields are easily discoverable during coding. Optional arguments can be left out. Configuration can happen all at once during struct initialisation, or individual fields can be set later in the lifecycle of the object.

For more complex operations, where the underlying operation semantics allow create/update/delete behaviour, we provide simple factory helpers.


// Create a ManageOffer operation configured for deletion
op, err := DeleteOfferOp(offerID)

Try it out

If you’re interested in trying out the code, head to our GitHub repo and grab the latest release. At our developers site, all the Stellar operations are summarised in a handy reference.

For a more in-depth look at the available functionality, check out the GoDocs for horizonclient and txnbuild. These contain many usage examples, including samples for all operations. If you’re ready to build something more involved, there a look at our more extensive command line demo, which creates and destroys accounts on the Stellar Testnet.

This library is under active development and we’d love your feedback! Please report bugs and missing functionality here. For general questions about this SDK, Horizon or other Stellar topics, the Stellar Stack Exchange is a great resource. Lastly, if you want to chat, join the community! You’ll find myself and other SDF developers hanging out in the stellar.public team on Keybase.