assets
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseStellar Assets, Trustlines, and SAC
Stellar资产、信任线与SAC
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的原生代币机制:经典资产发行、信任线,以及让经典资产可在Soroban中使用的Stellar Asset Contract(SAC)桥接方案。除非需要自定义逻辑,否则优先选择经典资产而非自定义Soroban代币。
When to use this skill
何时使用该技能
- Issuing a new asset (stablecoin, security token, utility token)
- Setting up trustlines from a client or contract
- Managing issuer flags (auth required, auth revocable, clawback)
- Bridging a classic asset into a Soroban contract via SAC
- Building regulated-asset flows (compliance, KYC, freeze)
- 发行新资产(稳定币、证券型代币、实用型代币)
- 从客户端或合约设置信任线
- 管理发行方标识(需授权、可撤销授权、赎回)
- 通过SAC将经典资产桥接至Soroban合约
- 构建受监管资产流程(合规、KYC、冻结)
Related skills
相关技能
- Custom token contracts (when classic isn't enough) →
../soroban/SKILL.md - UI flows for trustline creation and asset display →
../dapp/SKILL.md - Looking up balances and trustline state →
../data/SKILL.md - Token-related SEPs (SEP-41, SEP-7, etc.) →
../standards/SKILL.md
- 自定义代币合约(经典方案无法满足需求时)→
../soroban/SKILL.md - 信任线创建与资产展示的UI流程 →
../dapp/SKILL.md - 查询余额与信任线状态 →
../data/SKILL.md - 代币相关SEP标准(SEP-41、SEP-7等)→
../standards/SKILL.md
Overview
概述
Stellar has two token mechanisms:
- Stellar Assets (Classic): Built-in, highly efficient, full ecosystem support
- Soroban Tokens: Custom contracts with flexible logic
Recommendation: Prefer Stellar Assets unless you need custom token logic.
Stellar拥有两种代币机制:
- Stellar Assets(经典版):内置功能、高效、全生态支持
- Soroban代币:具备灵活逻辑的自定义合约
建议:除非需要自定义代币逻辑,否则优先选择Stellar Assets。
Stellar Assets (Classic)
Stellar Assets(经典版)
Asset Types
资产类型
| Type | Description |
|---|---|
| Native (XLM) | Stellar's native currency, no trustline needed |
| Credit | Issued by an account, requires trustline |
| Liquidity Pool Shares | Represent LP positions |
| 类型 | 描述 |
|---|---|
| Native (XLM) | Stellar原生货币,无需信任线 |
| Credit | 由账户发行,需要信任线 |
| Liquidity Pool Shares | 代表流动性池头寸 |
Asset Identifiers
资产标识符
typescript
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)typescript
import * as StellarSdk from "@stellar/stellar-sdk";
// 原生XLM
const xlm = StellarSdk.Asset.native();
// 信用资产(代码 + 发行方)
const usdc = new StellarSdk.Asset(
"USDC",
"GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN"
);
// 资产代码规则:
// - 1-4字符:字母数字(credit_alphanum4)
// - 5-12字符:字母数字(credit_alphanum12)Issuing Assets
发行资产
Create Issuing Account
创建发行账户
typescript
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()}`);typescript
import * as StellarSdk from "@stellar/stellar-sdk";
const server = new StellarSdk.Horizon.Server("https://horizon-testnet.stellar.org");
// 1. 创建发行账户(应与分发账户分离)
const issuerKeypair = StellarSdk.Keypair.random();
const distributorKeypair = StellarSdk.Keypair.random();
// 2. 为账户注资(测试网)
await fetch(`https://friendbot.stellar.org?addr=${issuerKeypair.publicKey()}`);
await fetch(`https://friendbot.stellar.org?addr=${distributorKeypair.publicKey()}`);Issue Asset
发行资产
typescript
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);typescript
const asset = new StellarSdk.Asset("MYTOKEN", issuerKeypair.publicKey());
// 1. 分发账户向发行方创建信任线
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", // 最大持有量
})
)
.setTimeout(180)
.build();
trustlineTx.sign(distributorKeypair);
await server.submitTransaction(trustlineTx);
// 2. 发行方向分发账户发送代币
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);Lock Issuing Account
锁定发行账户
For fixed-supply tokens, lock the issuer:
typescript
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对于固定供应量代币,锁定发行方:
typescript
const lockTx = new StellarSdk.TransactionBuilder(issuerAccount, {
fee: StellarSdk.BASE_FEE,
networkPassphrase: StellarSdk.Networks.TESTNET,
})
.addOperation(
StellarSdk.Operation.setOptions({
masterWeight: 0, // 禁用主密钥
})
)
.setTimeout(180)
.build();
lockTx.sign(issuerKeypair);
await server.submitTransaction(lockTx);
// 发行方无法再发行更多代币Asset Flags
资产标识
Configure issuer account flags for compliance:
typescript
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();配置发行方账户标识以满足合规要求:
typescript
const setFlagsTx = new StellarSdk.TransactionBuilder(issuerAccount, {
fee: StellarSdk.BASE_FEE,
networkPassphrase: StellarSdk.Networks.TESTNET,
})
.addOperation(
StellarSdk.Operation.setOptions({
setFlags:
StellarSdk.AuthRequiredFlag | // 信任线需审批
StellarSdk.AuthRevocableFlag | // 可冻结信任线
StellarSdk.AuthClawbackEnabledFlag, // 可赎回代币
})
)
.setTimeout(180)
.build();Flag Descriptions
标识说明
| Flag | Effect |
|---|---|
| Users must get approval before receiving tokens |
| Issuer can freeze user balances |
| Flags cannot be changed (permanent) |
| Issuer can clawback tokens from accounts |
| 标识 | 作用 |
|---|---|
| 用户接收代币前必须获得审批 |
| 发行方可冻结用户余额 |
| 标识无法修改(永久生效) |
| 发行方可从账户中赎回代币 |
Authorize Trustline
授权信任线
typescript
// 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();typescript
// 当设置AUTH_REQUIRED时,审批信任线:
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, // 部分授权
},
})
)
.setTimeout(180)
.build();Clawback Tokens
赎回代币
typescript
// 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();typescript
// 需要启用AUTH_CLAWBACK_ENABLED标识
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();Trustlines
信任线
Create Trustline
创建信任线
typescript
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();typescript
const changeTrustTx = new StellarSdk.TransactionBuilder(userAccount, {
fee: StellarSdk.BASE_FEE,
networkPassphrase: StellarSdk.Networks.TESTNET,
})
.addOperation(
StellarSdk.Operation.changeTrust({
asset: asset,
limit: "10000", // 设置为0可移除信任线
})
)
.setTimeout(180)
.build();Check Trustline Status
检查信任线状态
typescript
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);
}typescript
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("余额:", trustline.balance);
console.log("限额:", trustline.limit);
console.log("已授权:", trustline.is_authorized);
}Stellar Asset Contract (SAC)
Stellar Asset Contract(SAC)
SAC provides Soroban interface for Stellar Assets, enabling smart contract interactions.
SAC为Stellar Assets提供Soroban接口,支持智能合约交互。
Deploy SAC for Existing Asset
为现有资产部署SAC
bash
undefinedbash
undefinedGet the SAC address for an asset
获取资产对应的SAC地址
stellar contract asset deploy
--asset USDC:GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN
--source alice
--network testnet
--asset USDC:GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN
--source alice
--network testnet
undefinedstellar contract asset deploy
--asset USDC:GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN
--source alice
--network testnet
--asset USDC:GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN
--source alice
--network testnet
undefinedSAC Address Derivation
SAC地址推导
typescript
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 addresstypescript
import * as StellarSdk from "@stellar/stellar-sdk";
const asset = new StellarSdk.Asset("USDC", issuerPublicKey);
const contractId = asset.contractId(StellarSdk.Networks.TESTNET);
// 返回确定性的SAC合约地址Using SAC in Soroban Contracts
在Soroban合约中使用SAC
rust
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);
}rust
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();
// 使用标准代币接口
let token = TokenClient::new(&env, &asset_contract);
token.transfer(&from, &to, &amount);
}SAC vs Custom Token Interface
SAC与自定义代币接口对比
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() -> Symbol
SAC实现了标准Soroban代币接口:
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() -> Symbol
When to Use What
方案选择指南
Use Stellar Assets When:
选择Stellar Assets的场景:
- Standard fungible token (currency, stablecoin)
- Need full ecosystem support (wallets, exchanges)
- Regulatory compliance features (freeze, clawback)
- Performance critical (classic operations are cheaper)
- DEX integration via order book
- 标准 fungible 代币(货币、稳定币)
- 需要全生态支持(钱包、交易所)
- 合规需求(冻结、赎回)
- 性能优先(经典操作成本更低)
- 通过订单簿集成DEX
Use Soroban Custom Tokens When:
选择Soroban自定义代币的场景:
- Complex transfer logic (royalties, fees, restrictions)
- Custom authorization schemes
- Non-standard token behaviors
- Integration with custom DeFi contracts
- NFTs or semi-fungible tokens
- 复杂转账逻辑(版税、手续费、限制)
- 自定义授权方案
- 非标准代币行为
- 与自定义DeFi合约集成
- NFT或半 fungible 代币
Use SAC When:
选择SAC的场景:
- Need Stellar Asset in Soroban contract
- Building DeFi protocols with existing assets
- Bridge between classic and smart contract operations
- 需要在Soroban合约中使用Stellar Asset
- 基于现有资产构建DeFi协议
- 实现经典操作与智能合约操作的桥接
Querying Assets
查询资产
Get Account Balances
获取账户余额
typescript
const 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);
}
}typescript
const 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);
}
}Find Assets
查找资产
typescript
// 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();typescript
// 按代码搜索资产
const assets = await server
.assets()
.forCode("USDC")
.call();
// 获取特定资产详情
const assetDetails = await server
.assets()
.forCode("USDC")
.forIssuer(issuerPublicKey)
.call();Get Asset Statistics
获取资产统计数据
typescript
const stats = await server
.assets()
.forCode("USDC")
.forIssuer(issuerPublicKey)
.call();
// stats includes:
// - amount: total issued
// - num_accounts: trustline count
// - flags: issuer flagstypescript
const stats = await server
.assets()
.forCode("USDC")
.forIssuer(issuerPublicKey)
.call();
// stats包含:
// - amount: 总发行量
// - num_accounts: 信任线数量
// - flags: 发行方标识SEP Standards for Assets
资产相关SEP标准
SEP-0001 (stellar.toml)
SEP-0001(stellar.toml)
Publish asset metadata in your domain's :
/.well-known/stellar.tomltoml
[[CURRENCIES]]
code = "MYTOKEN"
issuer = "GABC..."
display_decimals = 2
name = "My Token"
desc = "A description of my token"
image = "https://example.com/token-logo.png"在域名的中发布资产元数据:
/.well-known/stellar.tomltoml
[[CURRENCIES]]
code = "MYTOKEN"
issuer = "GABC..."
display_decimals = 2
name = "My Token"
desc = "A description of my token"
image = "https://example.com/token-logo.png"SEP-0010 (Web Authentication)
SEP-0010(Web身份验证)
Authenticate users with their Stellar accounts:
typescript
// Server generates challenge
// Client signs with wallet
// Server verifies signature通过Stellar账户验证用户身份:
typescript
// 服务器生成挑战
// 客户端使用钱包签名
// 服务器验证签名SEP-0024 (Hosted Deposit/Withdrawal)
SEP-0024(托管存提服务)
For fiat on/off ramps:
typescript
// Interactive flow for deposits/withdrawals
// Anchor handles KYC and fiat transfer用于法币出入金:
typescript
// 存提交互流程
// 锚点处理KYC与法币转账SEP-0045 (Web Auth for Contract Accounts)
SEP-0045(合约账户Web身份验证)
Extends SEP-10 to support Soroban contract accounts ( addresses) for web authentication. Required for smart wallet / passkey-based anchor integrations. See SEP-0045.
C...将SEP-10扩展至支持Soroban合约账户(地址)的Web身份验证。是智能钱包/基于密钥的锚点集成的必要条件。详见SEP-0045。
C...SEP-0050 (Non-Fungible Tokens)
SEP-0050(非 fungible 代币)
Standard contract interface for NFTs on Soroban. Reference implementations available in OpenZeppelin Stellar Contracts with Base, Consecutive, and Enumerable variants. See SEP-0050.
Soroban上NFT的标准合约接口。参考实现可在OpenZeppelin Stellar Contracts中找到,包含基础版、连续版与可枚举版。详见SEP-0050。
Best Practices
最佳实践
Asset Issuance
资产发行
- Use separate issuing and distribution accounts
- Lock issuer after initial distribution for fixed supply
- Publish stellar.toml with asset metadata
- Consider multisig for issuer account
- 使用独立的发行账户与分发账户
- 初始分发完成后锁定发行方以固定供应量
- 发布包含资产元数据的stellar.toml
- 考虑为发行方账户使用多签
Trustline Management
信任线管理
- Check trustline exists before sending payments
- Handle trustline creation in onboarding flow
- Respect trustline limits
- Monitor for frozen/deauthorized status
- 发送支付前检查信任线是否存在
- 在入职流程中处理信任线创建
- 遵守信任线限额
- 监控冻结/取消授权状态
Security
安全
- Validate asset issuer, not just code
- Be cautious of assets with clawback enabled
- Verify stellar.toml from authoritative source
- Use well-known asset lists for common tokens
- 验证资产发行方,而非仅验证代码
- 谨慎使用支持赎回功能的资产
- 从权威来源验证stellar.toml
- 针对常见代币使用知名资产列表