Skip to main content
When performing payments on Stellar for Stellar Assets other than XLM, it is important to ensure that the receiving account has a trustline established for the asset being sent. This one-pager provides a quick overview of how to verify trustlines before sending transactions, ensuring that payments are processed smoothly and allowing for application to appropriately handle cases where trustlines are not established or invalid.

Why Verify Trustlines?

In Stellar, trustlines are used to establish a relationship between an account and a Stellar Asset. They are created with the change trust operation, and indicate that the account is willing to hold and transact with that asset. If a trustline is not established for an asset, the account cannot receive payments in that asset, leading to transaction failures. Furthermore, asset issuers may enforce specific requirements through trustlines, such as maximum balances an account can hold or granular authorization to receive/send the asset or to maintain liabilities. See the Asset Design Considerations for more details on how control flags and trustlines can be used to customize these behaviors. Verifying trustlines before sending transactions helps ensure that the receiving account meets the requirements and can successfully receive the asset. This allows for the application to handle cases where trustlines are not established or invalid, providing clear feedback and a smooth user experience while preventing failed transactions.

Checking a Trustline through the Stellar RPC

Unlike Horizon, Stellar RPC does not return an account’s trustlines alongside the account itself — a trustline is its own ledger entry, so you look it up directly. The JavaScript SDK gives you two ways to do that:
  • getAssetBalance is the quick path. One call tells you whether the trustline exists at all, whether it is authorized, and how much of the asset the account currently holds.
  • getLedgerEntries gives you the raw trustline entry, which you need when you also care about the trustline’s limit — the maximum balance the account is willing to hold.
Most applications only need the first. Reach for the second when a large payment could push the receiver past its limit.

Existence and authorization

The following snippet checks that the destination account exists, that it trusts the asset, and that the trustline is authorized to receive it:
getAssetBalance also accepts a contract address, so the same call verifies a Soroban contract’s balance of the asset through its Stellar Asset Contract.
getAssetBalance raises the same Trustline for CODE:ISSUER not found for ACCOUNT error whether the trustline is genuinely absent or the lookup simply failed — a timeout or an unreachable RPC endpoint surfaces as “not found” too. If your application needs to tell those cases apart, use getLedgerEntries instead: it returns an empty entries array for a missing trustline and only rejects on a transport error.

Checking the trustline limit

A trustline also carries a limit: the maximum balance of the asset the account is willing to hold. A payment that would push the balance past that limit fails, even when the trustline exists and is authorized. getAssetBalance does not surface the limit, so we fetch the raw trustline ledger entry with getLedgerEntries. Amounts are stored on the ledger as int64 stroops, and the largest representable amount — 922,337,203,685.4775807 — exceeds what a JavaScript Number can hold exactly. Trustline limits routinely sit at that maximum, so this example keeps the arithmetic in BigInt stroops; converting to Number first can silently misjudge whether a payment fits. See Amount precision for the full picture.

Checking a Trustline through the Stellar Asset Contract (SAC)

All Stellar assets, including the native asset (XLM), can be managed with smart contract transactions through Stellar Asset Contracts (SAC). SACs provide a smart contract interface for handling assets, allowing for more complex interactions and programmability. This means that it includes certain functions to help developers manage assets, such as verifying trustlines and sending payments, in a more flexible way than classic operations. For this example, we’ll be using SAC as a smart contract interface for the testnet USDC asset. A contract invocation transaction will be made to call the function authorized, which returns a boolean indicating whether the account’s trustline is authorized. This function can be accessed directly in a smart contract invocation as the example below demonstrates, or it can also be invoked by another contract, allowing for more complex interactions and programmability to be built in smart contracts. Note that authorized only reports the trustline’s authorization state. If the account has no trustline for the asset at all, the invocation does not return false — the simulation fails with Error(Contract, #13) (trustline entry is missing for account), so the two cases are handled in different branches below. If you also need to check the trustline’s limit, use the getLedgerEntries approach shown above.
To use the RPC example below you should first generate the contract bindings so the client can be used accordingly. This can be achieved through the Stellar CLI.E.g.: Generating the typescript bindings for the SAC of a given asset. The generated package takes its name from the output directory, so --output-dir=./sac is what makes import ... from "sac" below resolve:
Given a receiver address, the following code snippet demonstrates how to simulate a transaction to check if a trustline exists for a specific asset: