Skip to main content

Querying Data

Your application will be querying data from Horizon (one of Stellar's APIs) throughout its functionality. Information such as account balances, transaction history, sequence numbers for transactions, asset availability, and more are stored in Horizon’s database.

Here is a list of some common queries that you'll make.

note

In other places in this tutorial, we have omitted the JSDoc descriptions and typing for the sake of clean presentation. Here, we're including those to make these functions more copy/paste-able.

Imports and types

/src/lib/stellar/horizonQueries.js
import { error } from "@sveltejs/kit";
import {
Server,
TransactionBuilder,
Networks,
StrKey,
Asset,
} from "stellar-sdk";

const horizonUrl = "https://horizon-testnet.stellar.org";
const server = new Server(horizonUrl);

/**
* @module $lib/stellar/horizonQueries
* @description A collection of function that helps query various information
* from the [Horizon API](https://developers.stellar.org/api/horizon). This
* allows us to abstract and simplify some interactions so we don't have to have
* _everything_ contained within our `*.svelte` files.
*/

// We'll import some type definitions that already exists within the
// `stellar-sdk` package, so our functions will know what to expect.
/** @typedef {import('stellar-sdk').ServerApi.AccountRecord} AccountRecord */
/** @typedef {import('stellar-sdk').Horizon.ErrorResponseData} ErrorResponseData */
/** @typedef {import('stellar-sdk').ServerApi.PaymentOperationRecord} PaymentOperationRecord */
/** @typedef {import('stellar-sdk').Horizon.BalanceLine} BalanceLine */
/** @typedef {import('stellar-sdk').Horizon.BalanceLineAsset} BalanceLineAsset */
/** @typedef {import('stellar-sdk').Transaction} Transaction */
/** @typedef {import('stellar-sdk').ServerApi.PaymentPathRecord} PaymentPathRecord */

Source: https://github.com/stellar/basic-payment-app/blob/main/src/lib/stellar/horizonQueries.js

fetchAccount

Gives an account's sequence number, asset balances, and trustlines.

/src/lib/stellar/horizonQueries.js
/**
* Fetches and returns details about an account on the Stellar network.
* @async
* @function fetchAccount
* @param {string} publicKey Public Stellar address to query information about
* @returns {Promise<AccountRecord>} Object containing whether or not the account is funded, and (if it is) account details
* @throws {error} Will throw an error if the account is not funded on the Stellar network, or if an invalid public key was provided.
*/
export async function fetchAccount(publicKey) {
if (StrKey.isValidEd25519PublicKey(publicKey)) {
try {
let account = await server.accounts().accountId(publicKey).call();
return account;
} catch (err) {
// @ts-ignore
if (err.response?.status === 404) {
throw error(404, "account not funded on network");
} else {
// @ts-ignore
throw error(err.response?.status ?? 400, {
// @ts-ignore
message: `${err.response?.title} - ${err.response?.detail}`,
});
}
}
} else {
throw error(400, { message: "invalid public key" });
}
}

Source: https://github.com/stellar/basic-payment-app/blob/main/src/lib/stellar/horizonQueries.js

fetchAccountBalances

Gets existing balances for a given publicKey.

/src/lib/stellar/horizonQueries.js
/**
* Fetches and returns balance details for an account on the Stellar network.
* @async
* @function fetchAccountBalances
* @param {string} publicKey Public Stellar address holding balances to query
* @returns {Promise<BalanceLine[]>} Array containing balance information for each asset the account holds
*/
export async function fetchAccountBalances(publicKey) {
const { balances } = await fetchAccount(publicKey);
return balances;
}

Source: https://github.com/stellar/basic-payment-app/blob/main/src/lib/stellar/horizonQueries.js

fetchRecentPayments

Finds any payments made to or from the given publicKey (includes: payments, path payments, and account merges).

/src/lib/stellar/horizonQueries.js
/**
* Fetches and returns recent `payment`, `createAccount` operations that had an effect on this account.
* @async
* @function fetchRecentPayments
* @param {string} publicKey Public Stellar address to query recent payment operations to/from
* @param {number} [limit] Number of operations to request from the server
* @returns {Promise<PaymentOperationRecord[]>} Array containing details for each recent payment
*/
export async function fetchRecentPayments(publicKey, limit = 10) {
const { records } = await server
.payments()
.forAccount(publicKey)
.limit(limit)
.order("desc")
.call();
return records;
}

Source: https://github.com/stellar/basic-payment-app/blob/main/src/lib/stellar/horizonQueries.js

submit

Submit a signed transaction to the Stellar network.

/src/lib/stellar/horizonQueries.js
/**
* Submits a Stellar transaction to the network for inclusion in the ledger.
* @async
* @function submit
* @param {Transaction} transaction Built transaction to submit to the network
* @throws Will throw an error if the transaction is not submitted successfully.
*/
export async function submit(transaction) {
try {
await server.submitTransaction(transaction);
} catch (err) {
throw error(400, {
// @ts-ignore
message: `${err.response?.title} - ${err.response?.data.extras.result_codes}`,
});
}
}

Source: https://github.com/stellar/basic-payment-app/blob/main/src/lib/stellar/horizonQueries.js

fetchAssetsWithHomeDomains

We create a brand new HomeDomainBalanceLine type that includes the balance information of a user's trustline, and also adds the home_domain of the asset issuer. If you're using something else for type safety (or nothing at all), feel free to adapt or ignore the @typedefs we've included here.

Then, it looks at all the issuer accounts and returns only the ones with a home_domain set on the account.

/src/lib/stellar/horizonQueries.js
/**
* @typedef {Object} HomeDomainObject
* @property {string} home_domain Domain name the issuer of this asset has set for their account on the Stellar network.
*/

/** @typedef {BalanceLineAsset & HomeDomainObject} HomeDomainBalanceLine */

/**
* Fetches `home_domain` from asset issuer accounts on the Stellar network and returns an array of balances.
* @async
* @function fetchAssetsWithHomeDomains
* @param {BalanceLine[]} balances Array of balances to query issuer accounts of
* @returns {Promise<HomeDomainBalanceLine[]>} Array of balance details for assets that do have a `home_domain` setting
*/
export async function fetchAssetsWithHomeDomains(balances) {
let homeDomains = await Promise.all(
balances.map(async (asset) => {
// We are only interested in issued assets (i.e., not LPs and not XLM)
if ("asset_issuer" in asset) {
// Fetch the account from the network, and add its info to the array, along with the home_domain
let account = await fetchAccount(asset.asset_issuer);
if ("home_domain" in account) {
return {
...asset,
home_domain: account.home_domain,
};
}
}
}),
);

// Filter out any null array entries before returning
// @ts-ignore
return homeDomains.filter((balance) => balance);
}

Source: https://github.com/stellar/basic-payment-app/blob/main/src/lib/stellar/horizonQueries.js

findStrictSendPaths

Find the available strict send paths between a source asset/amount and receiving account.

/src/lib/stellar/horizonQueries.js
/**
* Fetches available paths on the Stellar network between the destination account, and the asset sent by the source account.
* @async
* @function findStrictSendPaths
* @param {Object} opts Options object
* @param {string} opts.sourceAsset Stellar asset which will be sent from the source account
* @param {string|number} opts.sourceAmount Amount of the Stellar asset that should be debited from the srouce account
* @param {string} opts.destinationPublicKey Public Stellar address that will receive the destination asset
* @returns {Promise<PaymentPathRecord[]>} Array of payment paths that can be selected for the transaction
* @throws Will throw an error if there are no available payment paths.
*/
export async function findStrictSendPaths({
sourceAsset,
sourceAmount,
destinationPublicKey,
}) {
let asset =
sourceAsset === "native"
? Asset.native()
: new Asset(sourceAsset.split(":")[0], sourceAsset.split(":")[1]);
let response = await server
.strictSendPaths(asset, sourceAmount.toString(), destinationPublicKey)
.call();
if (response.records.length > 0) {
return response.records;
} else {
throw error(400, { message: "no strict send paths available" });
}
}

Source: https://github.com/stellar/basic-payment-app/blob/main/src/lib/stellar/horizonQueries.js

findStrictReceivePaths

Find the available strict receive paths between a source account and receiving asset/amount.

/src/lib/stellar/horizonQueries.js
/**
* Fetches available paths on the Stellar network between the source account, and the asset to be received by the destination.
* @async
* @function findStrictReceivePaths
* @param {Object} opts Options object
* @param {string} opts.sourcePublicKey Public Stellar address that will be the source of the payment operation
* @param {string} opts.destinationAsset Stellar asset which should be received in the destination account
* @param {string|number} opts.destinationAmount Amount of the Stellar asset that should be credited to the destination account
* @returns {Promise<PaymentPathRecord[]>} Array of payment paths that can be selected for the transaction
* @throws Will throw an error if there are no available payment paths.
*/
export async function findStrictReceivePaths({
sourcePublicKey,
destinationAsset,
destinationAmount,
}) {
let asset =
destinationAsset === "native"
? Asset.native()
: new Asset(
destinationAsset.split(":")[0],
destinationAsset.split(":")[1],
);
let response = await server
.strictReceivePaths(sourcePublicKey, asset, destinationAmount.toString())
.call();
if (response.records.length > 0) {
return response.records;
} else {
throw error(400, { message: "no strict receive paths available" });
}
}

Source: https://github.com/stellar/basic-payment-app/blob/main/src/lib/stellar/horizonQueries.js

Query Stellar Expert

Stellar Expert is a third-party block explorer that is indispensable as a tool for understanding what is happening on the Stellar network. On our /dashboard/assets page, we're pre-populating a list of asset trustlines a user might choose to add to their Stellar account. We get this list of assets from the Stellar Expert API.

note

Stellar Expert employs their own algorithm to determine the quality of an asset. This algorithm considers things like the number of payments made using an asset, the number of accounts holding that asset, how much of the asset is available on the DEX or in liquidity pools, and so on. These rankings aren't a "final determination" of an asset's quality by any means, and are more like an observation of which Stellar assets see the most use and activity on the network.

We've created our own RankedAsset type so BasicPay knows how to interact with these objects. And we are then retrieving the ten most highly-rated assets from the Stellar Expert API.

/src/lib/utils/stellarExpert.js
const network = "testnet";
const baseUrl = `https://api.stellar.expert/explorer/${network}`;

/**
* An asset object that has been returned by our query to Stellar.Expert
* @typedef {Object} RankedAsset
* @property {string} asset Asset identifier
* @property {number} traded_amount Total traded amount (in stroops)
* @property {number} payments_amount Total payments amount (in stroops)
* @property {number} created Timestamp of the first recorder operation with asset
* @property {number} supply Total issued asset supply
* @property {Object} trustlines Trustlines established to an asset
* @property {number} trades Total number of trades
* @property {number} payments Total number of payments
* @property {string} domain Associated `home_domain`
* @property {Object} tomlInfo Asset information from stellar.toml file
* @property {Object} rating Composite asset rating
* @property {number} paging_token Paging token
* @see {@link https://stellar.expert/openapi.html#tag/Asset-Info-API/operation/getAllAssets}
*/

/**
* Fetches and returns the most highly rated assets, according to the Stellar.Expert calculations.
* @async
* @function fetchAssets
* @returns {Promise<RankedAsset[]>} Array of objects containing details for each asset
*/
export async function fetchAssets() {
let res = await fetch(
`${baseUrl}/asset?${new URLSearchParams({
// these are all the defaults, but you could customize them if needed
search: "",
sort: "rating",
order: "desc",
limit: "10",
cursor: "0",
})}`,
);
let json = await res.json();

let records = json._embedded.records;
return records;
}

Source: https://github.com/stellar/basic-payment-app/blob/main/src/lib/utils/stellarExpert.js