From stellar-dev
Issues and manages Stellar classic assets, trustlines, authorization flags, clawback, and the SAC bridge to Soroban. Use when tokenizing assets, issuing stablecoins, or bridging to Soroban contracts.
How this skill is triggered — by the user, by Claude, or both
Slash command
/stellar-dev:assets [asset task][asset task]The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Stellar's native token mechanism: classic asset issuance, trustlines, and the Stellar Asset Contract (SAC) bridge that makes classic assets usable from Soroban. Default to classic assets over custom Soroban tokens unless you need custom logic.
Stellar's native token mechanism: classic asset issuance, trustlines, and the Stellar Asset Contract (SAC) bridge that makes classic assets usable from Soroban. Default to classic assets over custom Soroban tokens unless you need custom logic.
../soroban/SKILL.md../dapp/SKILL.md../data/SKILL.md../standards/SKILL.mdStellar has two token mechanisms:
Recommendation: Prefer Stellar Assets unless you need custom token logic.
| Type | Description |
|---|---|
| Native (XLM) | Stellar's native currency, no trustline needed |
| Credit | Issued by an account, requires trustline |
| Liquidity Pool Shares | Represent LP positions |
import * as StellarSdk from "@stellar/stellar-sdk";
// Native XLM
const xlm = StellarSdk.Asset.native();
// Credit asset (code + issuer)
const usdc = new StellarSdk.Asset(
"USDC",
"GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN"
);
// Asset code rules:
// - 1-4 chars: alphanumeric (credit_alphanum4)
// - 5-12 chars: alphanumeric (credit_alphanum12)
import * as StellarSdk from "@stellar/stellar-sdk";
const server = new StellarSdk.Horizon.Server("https://horizon-testnet.stellar.org");
// 1. Create issuing account (should be separate from distribution)
const issuerKeypair = StellarSdk.Keypair.random();
const distributorKeypair = StellarSdk.Keypair.random();
// 2. Fund accounts (testnet)
await fetch(`https://friendbot.stellar.org?addr=${issuerKeypair.publicKey()}`);
await fetch(`https://friendbot.stellar.org?addr=${distributorKeypair.publicKey()}`);
const asset = new StellarSdk.Asset("MYTOKEN", issuerKeypair.publicKey());
// 1. Distributor creates trustline to issuer
const distributorAccount = await server.loadAccount(distributorKeypair.publicKey());
const trustlineTx = new StellarSdk.TransactionBuilder(distributorAccount, {
fee: StellarSdk.BASE_FEE,
networkPassphrase: StellarSdk.Networks.TESTNET,
})
.addOperation(
StellarSdk.Operation.changeTrust({
asset: asset,
limit: "1000000", // Max amount to hold
})
)
.setTimeout(180)
.build();
trustlineTx.sign(distributorKeypair);
await server.submitTransaction(trustlineTx);
// 2. Issuer sends tokens to distributor
const issuerAccount = await server.loadAccount(issuerKeypair.publicKey());
const issueTx = new StellarSdk.TransactionBuilder(issuerAccount, {
fee: StellarSdk.BASE_FEE,
networkPassphrase: StellarSdk.Networks.TESTNET,
})
.addOperation(
StellarSdk.Operation.payment({
destination: distributorKeypair.publicKey(),
asset: asset,
amount: "1000000",
})
)
.setTimeout(180)
.build();
issueTx.sign(issuerKeypair);
await server.submitTransaction(issueTx);
For fixed-supply tokens, lock the issuer:
const lockTx = new StellarSdk.TransactionBuilder(issuerAccount, {
fee: StellarSdk.BASE_FEE,
networkPassphrase: StellarSdk.Networks.TESTNET,
})
.addOperation(
StellarSdk.Operation.setOptions({
masterWeight: 0, // Disable master key
})
)
.setTimeout(180)
.build();
lockTx.sign(issuerKeypair);
await server.submitTransaction(lockTx);
// Issuer can never issue more tokens
Configure issuer account flags for compliance:
const setFlagsTx = new StellarSdk.TransactionBuilder(issuerAccount, {
fee: StellarSdk.BASE_FEE,
networkPassphrase: StellarSdk.Networks.TESTNET,
})
.addOperation(
StellarSdk.Operation.setOptions({
setFlags:
StellarSdk.AuthRequiredFlag | // Trustlines require approval
StellarSdk.AuthRevocableFlag | // Can freeze trustlines
StellarSdk.AuthClawbackEnabledFlag, // Can clawback tokens
})
)
.setTimeout(180)
.build();
| Flag | Effect |
|---|---|
AUTH_REQUIRED | Users must get approval before receiving tokens |
AUTH_REVOCABLE | Issuer can freeze user balances |
AUTH_IMMUTABLE | Flags cannot be changed (permanent) |
AUTH_CLAWBACK_ENABLED | Issuer can clawback tokens from accounts |
// When AUTH_REQUIRED is set, approve trustlines:
const authorizeTx = new StellarSdk.TransactionBuilder(issuerAccount, {
fee: StellarSdk.BASE_FEE,
networkPassphrase: StellarSdk.Networks.TESTNET,
})
.addOperation(
StellarSdk.Operation.setTrustLineFlags({
trustor: userPublicKey,
asset: asset,
flags: {
authorized: true,
// authorizedToMaintainLiabilities: true, // Partial auth
},
})
)
.setTimeout(180)
.build();
// Requires AUTH_CLAWBACK_ENABLED flag
const clawbackTx = new StellarSdk.TransactionBuilder(issuerAccount, {
fee: StellarSdk.BASE_FEE,
networkPassphrase: StellarSdk.Networks.TESTNET,
})
.addOperation(
StellarSdk.Operation.clawback({
asset: asset,
from: targetAccountId,
amount: "100",
})
)
.setTimeout(180)
.build();
const changeTrustTx = new StellarSdk.TransactionBuilder(userAccount, {
fee: StellarSdk.BASE_FEE,
networkPassphrase: StellarSdk.Networks.TESTNET,
})
.addOperation(
StellarSdk.Operation.changeTrust({
asset: asset,
limit: "10000", // 0 to remove trustline
})
)
.setTimeout(180)
.build();
const account = await server.loadAccount(userPublicKey);
const trustline = account.balances.find(
(b) =>
b.asset_type !== "native" &&
b.asset_code === "USDC" &&
b.asset_issuer === usdcIssuer
);
if (trustline) {
console.log("Balance:", trustline.balance);
console.log("Limit:", trustline.limit);
console.log("Authorized:", trustline.is_authorized);
}
SAC provides Soroban interface for Stellar Assets, enabling smart contract interactions.
# Get the SAC address for an asset
stellar contract asset deploy \
--asset USDC:GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN \
--source alice \
--network testnet
import * as StellarSdk from "@stellar/stellar-sdk";
const asset = new StellarSdk.Asset("USDC", issuerPublicKey);
const contractId = asset.contractId(StellarSdk.Networks.TESTNET);
// Returns the deterministic SAC contract address
use soroban_sdk::{token::Client as TokenClient, Address, Env};
pub fn transfer_asset(
env: Env,
from: Address,
to: Address,
asset_contract: Address,
amount: i128,
) {
from.require_auth();
// Use standard token interface
let token = TokenClient::new(&env, &asset_contract);
token.transfer(&from, &to, &amount);
}
SAC implements the standard Soroban token interface:
balance(id: Address) -> i128transfer(from: Address, to: Address, amount: i128)approve(from: Address, spender: Address, amount: i128, expiration_ledger: u32)allowance(from: Address, spender: Address) -> i128decimals() -> u32name() -> Stringsymbol() -> Symbolconst account = await server.loadAccount(publicKey);
for (const balance of account.balances) {
if (balance.asset_type === "native") {
console.log("XLM:", balance.balance);
} else {
console.log(`${balance.asset_code}:`, balance.balance);
}
}
// Search for assets by code
const assets = await server
.assets()
.forCode("USDC")
.call();
// Get specific asset details
const assetDetails = await server
.assets()
.forCode("USDC")
.forIssuer(issuerPublicKey)
.call();
const stats = await server
.assets()
.forCode("USDC")
.forIssuer(issuerPublicKey)
.call();
// stats includes:
// - amount: total issued
// - num_accounts: trustline count
// - flags: issuer flags
Publish asset metadata in your domain's /.well-known/stellar.toml:
[[CURRENCIES]]
code = "MYTOKEN"
issuer = "GABC..."
display_decimals = 2
name = "My Token"
desc = "A description of my token"
image = "https://example.com/token-logo.png"
Authenticate users with their Stellar accounts:
// Server generates challenge
// Client signs with wallet
// Server verifies signature
For fiat on/off ramps:
// Interactive flow for deposits/withdrawals
// Anchor handles KYC and fiat transfer
Extends SEP-10 to support Soroban contract accounts (C... addresses) for web authentication. Required for smart wallet / passkey-based anchor integrations. See SEP-0045.
Standard contract interface for NFTs on Soroban. Reference implementations available in OpenZeppelin Stellar Contracts with Base, Consecutive, and Enumerable variants. See SEP-0050.
npx claudepluginhub stellar/stellar-dev-skill --plugin stellar-devMaps Stellar Ecosystem Proposals (SEPs) and Core Advancement Proposals (CAPs) to use cases like wallets, anchors, payments, deposits, federation, deep links, and KYC. Also bundles ecosystem references and official docs.
Builds Stellar blockchain apps in Python using stellar-sdk. Covers transaction building/signing, Horizon/Soroban RPC queries, smart contract deployment, XDR/SCVal conversion, async workflows, and SEP integrations.
Build Helius-powered Solana applications: transaction sending (Sender), asset/NFT queries (DAS API), WebSocket/gRPC streaming, webhook pipelines, priority fees, wallet analysis, and agent onboarding.