Mark Tripoli I am HP Nonstop developer, who develops train control systems. I love open source projects and information and attempting to teach others new tools. I am a blockchain junkie and love its tech!

Stellar SDK Examples (Java)

  Reading Time:

In this post, I will be adding some examples of how to use the java-stellar-sdk. Hopefully this should give you a decent idea of how to utilize the SDK and give you some ideas.

Please note: This project is designed to help you implment the SDK in your own way. The way I have done things does constitute the absolute way.

If you are interested in using the SDK, please ensure you have been familiarized with Stellar and it's REST API Guide. I will not be covering what each operation means, that information is clearly described in their guide.

I will be updating this post over time. All code can be found on our Github Page, where there will be more examples and implementations.

Accounts

Create KeyPair
You need a KeyPair to for almost everything: Checking a balance, Sign TX's, etc.

KeyPair random = KeyPair.random();
KeyPair fromAccountId = KeyPair.fromAccountId("xxxxx");
KeyPair fromBip39Seed = KeyPair.fromBip39Seed();
KeyPair fromPublicKey = KeyPair.fromPublicKey(byte);
KeyPair fromSecretSeedByte = KeyPair.fromSecretSeed(byte);
KeyPair fromSecretSeedChar = KeyPair.fromSecretSeed(char);
KeyPair fromSecretSeedString = KeyPair.fromSecretSeed("xxx");
KeyPair fromXdrPublicKey = KeyPair.fromXdrPublicKey(key);
KeyPair fromXdrSignerKey = KeyPair.fromXdrSignerKey(signerKey);

Create Test Account
Very useful for application testing. The account is created by the Friend Bot sending you 10,000 XLM for funding.

public String createTestAccount ( KeyPair pair ) throws IOException {
    String friendbotUrl = String.format(
            "https://friendbot.stellar.org/?addr=%s",
            pair.getAccountId());
    InputStream response = new URL(friendbotUrl).openStream();
    return new Scanner(response, StandardCharsets.UTF_8).useDelimiter("\\A").next();
}

Check Native (XLM) Balance
Will display the balance of XLM in an account.

public String getNativeBalance ( KeyPair pair, boolean isMainNet )  {
    Server server = Connections.getServer ( isMainNet );
    String balanceAmount = null;
    try {
        AccountResponse.Balance[] balances = server.accounts().account(pair).getBalances();
        for (AccountResponse.Balance balance : balances)
        {
            if ( balance.getAssetType().equalsIgnoreCase( "native") )
            {
                balanceAmount = balance.getBalance();
            }
        }
    } catch  ( IOException | ErrorResponse e) { balanceAmount = "0"; }
    return balanceAmount;
}

Check All Token Balances
Will provide an array of all balances for an account

public StellarAsset[] getAllAssetBalances ( KeyPair pair, boolean isMainNet ) throws IOException
{
    Server server = Connections.getServer ( isMainNet );
    AccountResponse.Balance[] balances = server.accounts().account(pair).getBalances();
    StellarAsset[] assetBalances = new StellarAsset[balances.length];
    int i = 0;
    for ( AccountResponse.Balance balance : balances )
    {
        String assetName;
        if ( balance.getAssetType().equalsIgnoreCase("native") )
            assetName = "XLM";
        else
            assetName = balance.getAssetCode();
        assetBalances[i] = new StellarAsset(
                assetName, balance.getBalance() );
        i++;
    }
    return assetBalances;
}

Check All Receiving Transactions
Will return our cursor (for paging) and an array list of receiving Transactions (for that page) for a particular account.

public Pair<String, ArrayList<Transactions>> getReceivedTransactions (KeyPair keypair, String oldPagingToken, boolean isMainNet ) throws IOException
{
    String newPagingToken = null;
    Server server = Connections.getServer ( isMainNet );
    // Get up to 100 tx's for the current account
    PaymentsRequestBuilder paymentsRequest = server.payments().forAccount( keypair ).limit(100);
    ArrayList<Transactions> transactions = new ArrayList<>();
    Page<OperationResponse> page = paymentsRequest.execute();
    // if our paging token is null, position the cursor at the begining for oldest TX's
    // If not null, set the cursor at the location from the pagingToken
    if (oldPagingToken != null) {
        paymentsRequest.cursor(oldPagingToken);
    }
    for ( OperationResponse response : page.getRecords() )
    {
        // Update the paging token for our return
        newPagingToken = response.getPagingToken();
        // The payments stream includes both sent and received payments. We only
        // want to process received payments here.
        if ( response instanceof PaymentOperationResponse )
        {
            if ( !( ( PaymentOperationResponse ) response ).getFrom().getAccountId().equalsIgnoreCase ( keypair.getAccountId() ) )
            {
                String amount = ( ( PaymentOperationResponse ) response ).getAmount();
                String asset = Resolve.assetName( ( ( PaymentOperationResponse ) response ).getAsset() );
                String time = Format.time ( response.getCreatedAt() );
                /* just incase the public key is appended to the assetname */
                if ( asset.contains(":") )
                    asset = Format.cleanAssetName ( asset );
                transactions.add( new Transactions(
                        asset, amount, time, false) );
            }
            // now get the sent payments
            else {
                String amount = Format.sentPayment ( ( ( PaymentOperationResponse ) response ).getAmount() );
                String asset = Resolve.assetName( ( ( PaymentOperationResponse ) response ).getAsset() );
                String time = Format.time ( response.getCreatedAt() );
                /* just incase the public key is appended to the assetname */
                if ( asset.contains(":") )
                    asset = Format.cleanAssetName ( asset );
                transactions.add( new Transactions(
                        asset, amount, time, true) );
            }
        }
    }
    return new Pair<>(newPagingToken, transactions);
}

Transactions

Send a Payment
Here is a way to send a simple transaction.

public SubmitTransactionResponse sendPayment (boolean isMainNet, KeyPair srcPair,
                                              String destination, String amount,
                                              String memo) throws IOException
{
    Server server = Connections.getServer ( isMainNet );
    /* we already have the user's pair, but now we need to get the destinations */
    KeyPair destPair = KeyPair.fromAccountId(destination);
    /* now lets make sure the account exists */
    server.accounts().account(destPair);
    /* if there was no error, lets grab the current information on YOUR account */
    AccountResponse sourceAccount = server.accounts().account ( srcPair );
    /* build the tx */
    Transaction transaction = buildNativeTransaction ( sourceAccount, destPair, amount, memo );
    // Sign it
    transaction.sign(srcPair);
    /* send it off to the network */
     return sendTransaction ( transaction, server );
}
private Transaction buildNativeTransaction (AccountResponse sourceAccount, KeyPair destPair, String ammount, String memo )
{
    return  new Transaction.Builder ( sourceAccount )
            .addOperation ( new PaymentOperation.Builder(destPair, new AssetTypeNative (), ammount ).build() )
            // A memo allows you to add your own metadata to a transaction. It's
            // optional and does not affect how Stellar treats the transaction.
            .addMemo ( Memo.text ( memo ) )
            .build();
}
private SubmitTransactionResponse sendTransaction ( Transaction transaction, Server server ) throws IOException {
    return server.submitTransaction(transaction);
}

Custom Queries

You can also query Horizon directly. Say, to find out info on certain tokens.

package com.triippztech.queries;

import com.triippztech.models.Assets;
import com.triippztech.utils.Format;
import com.triippztech.utils.HorizonErrors;
import com.triippztech.utils.Props;
import com.triippztech.utils.Resolve;
import org.json.JSONArray;
import org.json.JSONObject;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Objects;
import java.util.TreeMap;

public class AssetQuery {
    private final static String EMBEDED = "_embedded";
    private final static String RECORDS = "records";
    private final static String LINKS = "_links";
    private final static String FLAGS = "flags";
    private final static String ASSET = "asset_code";
    private final static String NEXT = "next";
    private final static String HREF = "href";
    private final static String ISSUER = "asset_issuer";
    private final static String TOTAL_SUPP = "amount";
    private final static String ASSET_TYPE = "asset_type";
    private final static String PAGING_TOK = "paging_token";
    private final static String NUM_ACCOUNTS = "num_accounts";
    private final static String AUTH_REQ = "auth_required";
    private final static String AUTH_REVOC = "auth_revocable";

    public static TreeMap<String, String> getAllAssets (boolean isMainNet )
    {
        String json = null;
        TreeMap<String,String> assets = new TreeMap<>();
        boolean firstPass = true;
        String cursor = "";

        while (true)
        {
            try {
                if ( firstPass )
                {
                    if ( isMainNet )
                        json = queryHorizon(
                                Props.getProperty( Props.LUNAR_HELPER_PROPS, Props.MAIN_NET ) +
                                        Format.parseCursorUrl( Props.getProperty ( Props.LUNAR_HELPER_PROPS, Props.ALL_ASSETS ), cursor ) );
                    else
                        json = queryHorizon(
                                Props.getProperty( Props.LUNAR_HELPER_PROPS, Props.TEST_NET ) +
                                        Format.parseCursorUrl( Props.getProperty ( Props.LUNAR_HELPER_PROPS, Props.ALL_ASSETS ), cursor ) );

                    firstPass = false;
                    //json = queryHorizon ( cursor );
                } else {
                    json = queryHorizon ( cursor );
                }


            } catch ( IOException e )
            {
                e.printStackTrace();
            }

            JSONObject jsonObject = new JSONObject (Objects.requireNonNull(json));
            JSONObject embeded = jsonObject.getJSONObject ( EMBEDED );
            JSONArray records = embeded.getJSONArray ( RECORDS );

            /* make sure the record is not empty, if empty, we are done */
            if ( records.length() == 0 )
                break;

            for ( int i = 0; i < records.length(); i++ )
            {
                JSONObject newRecord = records.getJSONObject(i);

                /* looks like horizon does not automatically delete assets from their db
               because of this, it changes the asset code to "REMOVED"
               So once we hit "REMOVED" we will break out of this loop to kill the clutter
               and save some time.
                */
                if ( !newRecord.getString ( ASSET ).equalsIgnoreCase("REMOVE") ) {
                    assets.put ( newRecord.getString( ISSUER ), newRecord.getString ( ASSET ) );
                }
            }
            /* get the cursor for the next iteration */
            cursor = jsonObject.getJSONObject ( LINKS ).getJSONObject ( NEXT ).getString ( HREF );

        }
        return  assets;
    }

    @SuppressWarnings("Duplicates")
    public static Assets getAssetInfo ( boolean isMainNet, String assetCode ) throws Exception {
        Assets asset = null;
        String jsonString;
        String URL;

        if ( isMainNet ) {
            URL = Props.getProperty ( Props.LUNAR_HELPER_PROPS, Props.ASSET_C );
            if ( URL != null )
                URL = Props.getProperty( Props.LUNAR_HELPER_PROPS, Props.MAIN_NET ) + String.format ( URL, assetCode, "");
        }
        else {
            URL = Props.getProperty ( Props.LUNAR_HELPER_PROPS, Props.ASSET_C );
            if ( URL != null )
                URL = Props.getProperty( Props.LUNAR_HELPER_PROPS, Props.TEST_NET ) + String.format ( URL, assetCode, "");
        }

        try {
            jsonString = queryHorizon(URL);

            JSONObject jsonObject = new JSONObject ( jsonString );
            JSONObject embeded = jsonObject.getJSONObject ( EMBEDED );
            JSONArray records = embeded.getJSONArray ( RECORDS );

            try {
                records.getJSONObject(1);
                throw new Exception("1");
            } catch ( Exception e ) {
                System.out.println(records);
                //throw new Exception("1");
            }

            JSONObject newRecord = records.getJSONObject(0);

            asset = new Assets(
                    newRecord.getString ( ASSET ) ,
                    newRecord.getString ( TOTAL_SUPP ),
                    newRecord.getString ( ASSET_TYPE ),
                    newRecord.getString ( PAGING_TOK ),
                    newRecord.getString ( ISSUER ),
                    newRecord.getInt    ( NUM_ACCOUNTS ),
                    newRecord.getJSONObject(FLAGS).getBoolean( AUTH_REQ ),
                    newRecord.getJSONObject(FLAGS).getBoolean( AUTH_REVOC ) );
        } catch (IOException e) {
            e.printStackTrace();
        }
        return asset;
    }

    @SuppressWarnings("Duplicates")
    public static ArrayList<Assets> getAssetInfoArr (boolean isMainNet, String assetCode )
    {
        ArrayList<Assets> asset = new ArrayList<>();
        String json = null;
        String URL;
        String cursor = "";
        boolean firstPass = true;

        while (true)
        {
            try {
                if ( firstPass )
                {
                    if ( isMainNet ) {
                        URL = Props.getProperty ( Props.LUNAR_HELPER_PROPS, Props.ASSET_C );
                        if ( URL != null )
                            json = queryHorizon(Props.getProperty( Props.LUNAR_HELPER_PROPS, Props.MAIN_NET ) + String.format ( URL, assetCode, cursor) );
                    }
                    else {
                        URL = Props.getProperty ( Props.LUNAR_HELPER_PROPS, Props.ASSET_C );
                        if ( URL != null )
                            json = queryHorizon(Props.getProperty( Props.LUNAR_HELPER_PROPS, Props.TEST_NET ) + String.format ( URL, assetCode, cursor) );
                    }
                    firstPass = false;
                } else {
                    json = queryHorizon ( cursor );
                }
            } catch ( IOException e )
            {
                e.printStackTrace();
            }

            JSONObject jsonObject = new JSONObject (Objects.requireNonNull(json));
            JSONObject embeded = jsonObject.getJSONObject ( EMBEDED );
            JSONArray records = embeded.getJSONArray ( RECORDS );

            /* make sure the record is not empty, if empty, we are done */
            if ( records.length() == 0 )
                break;

            for ( int i = 0; i < records.length(); i++ )
            {
                JSONObject newRecord = records.getJSONObject(i);

                asset.add( new Assets(
                        newRecord.getString ( ASSET ) ,
                        newRecord.getString ( TOTAL_SUPP ),
                        newRecord.getString ( ASSET_TYPE ),
                        newRecord.getString ( PAGING_TOK ),
                        newRecord.getString ( ISSUER ),
                        newRecord.getInt    ( NUM_ACCOUNTS ),
                        newRecord.getJSONObject(FLAGS).getBoolean( AUTH_REQ ),
                        newRecord.getJSONObject(FLAGS).getBoolean( AUTH_REVOC ) ) );
            }
            /* get the cursor for the next iteration */
            cursor = jsonObject.getJSONObject ( LINKS ).getJSONObject ( NEXT ).getString ( HREF );
        }
        return  asset;
    }

    @SuppressWarnings("Duplicates")
    public static Assets getAssetInfo ( boolean isMainNet, String assetCode, String issuer ) throws Exception {
        Assets assets;
        String jsonString;
        String URL;

        if ( isMainNet ) {
            URL = Props.getProperty ( Props.LUNAR_HELPER_PROPS, Props.ASSET_CI );
            if ( URL != null )
                URL = Props.getProperty( Props.LUNAR_HELPER_PROPS, Props.MAIN_NET ) + String.format ( URL, assetCode, issuer);
        }
        else {
            URL = Props.getProperty ( Props.LUNAR_HELPER_PROPS, Props.ASSET_CI );
            if ( URL != null )
                URL = Props.getProperty( Props.LUNAR_HELPER_PROPS, Props.TEST_NET ) + String.format ( URL, assetCode, issuer);
        }

        try {
            jsonString = queryHorizon(URL);

            JSONObject jsonObject = new JSONObject ( jsonString );
            JSONObject embeded = jsonObject.getJSONObject ( EMBEDED );
            JSONArray records = embeded.getJSONArray ( RECORDS );

            JSONObject newRecord = records.getJSONObject(0);

            assets = new Assets(
                    newRecord.getString ( ASSET ) ,
                    newRecord.getString ( TOTAL_SUPP ),
                    newRecord.getString ( ASSET_TYPE ),
                    newRecord.getString ( PAGING_TOK ),
                    newRecord.getString ( ISSUER ),
                    newRecord.getInt    ( NUM_ACCOUNTS ),
                    newRecord.getJSONObject(FLAGS).getBoolean( AUTH_REQ ),
                    newRecord.getJSONObject(FLAGS).getBoolean( AUTH_REVOC ) ) ;


        } catch (IOException e) {
//            lunHelpLogger.error( e.getMessage() );
            throw new Exception( HorizonErrors.severReturnError ( e.getMessage() ) );
        }
        return assets;
    }

    @SuppressWarnings("Duplicates")
    public static ArrayList<Assets> getIssuerAssets ( boolean isMainNet, String issuer )
    {
        ArrayList<Assets> asset = new ArrayList<>();
        String jsonString;
        String URL;

        if ( isMainNet ) {
            URL = Props.getProperty ( Props.LUNAR_HELPER_PROPS, Props.ASSET_I );
            if ( URL != null )
                URL = Props.getProperty( Props.LUNAR_HELPER_PROPS, Props.MAIN_NET ) + String.format ( URL, issuer);
        }
        else {
            URL = Props.getProperty ( Props.LUNAR_HELPER_PROPS, Props.ASSET_I );
            if ( URL != null )
                URL = Props.getProperty( Props.LUNAR_HELPER_PROPS, Props.TEST_NET ) + String.format ( URL, issuer);
        }

        try {
            jsonString = queryHorizon(URL);

            JSONObject jsonObject = new JSONObject ( jsonString );
            JSONObject embeded = jsonObject.getJSONObject ( EMBEDED );
            JSONArray records = embeded.getJSONArray ( RECORDS );

            for ( int i = 0; i < records.length(); i++ )
            {
                JSONObject newRecord = records.getJSONObject(i);

                asset.add( new Assets(
                        newRecord.getString ( ASSET ) ,
                        newRecord.getString ( TOTAL_SUPP ),
                        newRecord.getString ( ASSET_TYPE ),
                        newRecord.getString ( PAGING_TOK ),
                        newRecord.getString ( ISSUER ),
                        newRecord.getInt    ( NUM_ACCOUNTS ),
                        newRecord.getJSONObject(FLAGS).getBoolean( AUTH_REQ ),
                        newRecord.getJSONObject(FLAGS).getBoolean( AUTH_REVOC ) ) );
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return asset;
    }


    private static String queryHorizon ( String URL ) throws IOException
    {
        return Resolve.getJSON ( URL );
    }
}

I will continue to update this over time. If you want me to add something, just drop a comment below and I will put something together for you! If anyone is interested in a full on tutorial, let me know.

Please consider a donation if you enjoy this work.

Creating Push Notifications With Java

In this tutorial, I will be showing you how to create push notifications using java. I will show you how to create one using SystemTray in...

Triippz Tech   Never miss a story from Triippz Tech, get updates in your inbox.