BluxBlux

Get SAC Address

Derive the Stellar Asset Contract (SAC) id of a classic asset — locally, with no network call.

getSacAddress returns the Stellar Asset Contract (SAC) id of a classic asset. Every classic asset — native XLM or a CODE:ISSUER pair — has a deterministic Soroban contract id derived from the asset plus the network passphrase. That contract, the SAC, is what lets Soroban contracts hold and move the asset.

The id is computed locally from the asset and passphrase, so there is no network call and the value is returned whether or not the SAC has actually been deployed yet. The function is synchronous — there is nothing to await.

Feed the result into getTokenMetadata, transfer's token option, or readContracts / writeContract to treat a classic asset as a Soroban token.

Type

import { Asset } from "@stellar/stellar-sdk";

// 'xlm' | 'native' | a 'CODE:ISSUER' string | an Asset instance.
type AssetArg = string | Asset;

const getSacAddress: (asset: AssetArg, network?: string) => string;
ParameterTypeDefaultDescription
assetstring | AssetRequired. The asset: "xlm"/"native", a "CODE:ISSUER" string, or an Asset instance.
networkstringactive networkNetwork passphrase to derive against. The SAC id differs per network.

The SAC id is network-specific — the same asset has a different SAC on testnet and mainnet because the passphrase is part of the derivation. Omit network to use the active network configured by createConfig, or pass one explicitly.

Usage

Native XLM

import { core } from "@bluxcc/core";

const xlmSac = core.getSacAddress("xlm");
console.log(xlmSac); // "C..."

An issued asset

Pass the asset in "CODE:ISSUER" form:

import { core } from "@bluxcc/core";

const usdcSac = core.getSacAddress(
  "USDC:GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN",
);

You can also pass an Asset instance:

import { core, StellarSdk } from "@bluxcc/core";

const usdc = new StellarSdk.Asset(
  "USDC",
  "GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN",
);

const usdcSac = core.getSacAddress(usdc);

Derive against a specific network

import { core, networks } from "@bluxcc/core";

const usdcSacOnMainnet = core.getSacAddress(
  "USDC:GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN",
  networks.mainnet,
);

Read a classic asset's token metadata

The SAC id is exactly what getTokenMetadata and the Soroban token helpers expect, so the two compose naturally:

import { core } from "@bluxcc/core";

const sac = core.getSacAddress(
  "USDC:GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN",
);

const metadata = await core.getTokenMetadata(sac);
// { decimals: 7, name: "USDC:GA5Z...", symbol: "USDC" }

Errors

getSacAddress throws synchronously with BLUX:-prefixed messages:

MessageCause
BLUX: getSacAddress needs a network passphrase — pass one, or call createConfig first.No network was passed and there is no active network (e.g. createConfig hasn't run).

It also propagates the underlying SDK error if asset is malformed (not "xlm"/"native", a valid "CODE:ISSUER" pair, or an Asset).

A SAC id is returned even when the contract has not been deployed on-chain yet. Deriving the id is free and offline; deploying or using the SAC is what touches the network. See the Stellar assets skill for the full SAC interop story.

On this page