Trustlines are required for accounts to hold and transact with non-native assets (anything other than XLM) on the Stellar network.
A trustline is an explicit opt-in configuration that authorizes a Stellar account to:
- Hold a specific asset
- Receive that asset
- Transact with that asset
Without a trustline, an account cannot receive or hold tokens like USDC, EURC, or any other asset.
- 0.5 XLM reserve: Each trustline requires 0.5 XLM in base reserve
- Increases minimum balance: Adds to the account's minimum balance requirement
- Prevents abuse: Limits spam and unauthorized asset creation
- Trust limit: Maximum amount the account is willing to hold
- Current balance: Tracks current holdings
- Liabilities: Records open offers and other obligations
interface Trustline {
assetCode: string; // Asset code (e.g., "USDC", "EURC")
issuer: string; // Asset issuer's Stellar address
limit?: string; // Optional: Maximum amount (defaults to max if not specified)
}{
assetCode: "USDC",
issuer: "CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA",
decimals: 10000000 // 7 decimals (divide by 10^7 for human-readable)
}{
assetCode: "EURC",
issuer: "GB3Q6QDZYTHWT7E5PVS3W7FUT5GVAFC5KSZFFLPU25GO7VTC3NM2ZTVO",
decimals: 10000000 // 7 decimals
}When deploying an escrow, you must specify the trustline(s) that will be used for the escrow funds.
{
"trustline": [
{
"assetCode": "USDC",
"issuer": "CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA"
}
]
}{
"trustline": [
{
"assetCode": "USDC",
"issuer": "CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA"
}
]
}All parties involved in the escrow must have trustlines established:
- Payer: Must have trustline to fund escrow
- Service Provider: Must have trustline to receive payments
- Receiver (if different): Must have trustline to receive funds
- Escrow Contract: Trustline is configured during deployment
import { Server, Asset, Keypair, Operation } from 'stellar-sdk';
async function establishTrustline(accountKeypair: Keypair, assetCode: string, issuer: string) {
const server = new Server('https://horizon.stellar.org');
const account = await server.loadAccount(accountKeypair.publicKey());
const asset = new Asset(assetCode, issuer);
const transaction = new TransactionBuilder(account, {
fee: '100',
networkPassphrase: Network.PUBLIC
})
.addOperation(
Operation.changeTrust({
asset: asset,
limit: '922337203685.4775807' // Max int64
})
)
.setTimeout(30)
.build();
transaction.sign(accountKeypair);
await server.submitTransaction(transaction);
}If using Stellar Wallet Kit in React/Next.js:
import { useWallet } from '@stellar/wallet-kit';
function TrustlineSetup() {
const { signTransaction } = useWallet();
async function establishTrustline(assetCode: string, issuer: string) {
// Build changeTrust operation
const operation = {
type: 'changeTrust',
asset: {
code: assetCode,
issuer: issuer
},
limit: '922337203685.4775807'
};
// Sign and submit via wallet
const signedTx = await signTransaction(operation);
// Submit to network...
}
}export const TRUSTLINES = [
{
name: "USDC",
address: "CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA",
decimals: 10000000,
assetCode: "USDC"
},
{
name: "EURC",
address: "GB3Q6QDZYTHWT7E5PVS3W7FUT5GVAFC5KSZFFLPU25GO7VTC3NM2ZTVO",
decimals: 10000000,
assetCode: "EURC"
}
];
// Helper function to get trustline config
export function getTrustlineConfig(assetCode: string) {
const trustline = TRUSTLINES.find(t => t.assetCode === assetCode);
if (!trustline) {
throw new Error(`Trustline not found for ${assetCode}`);
}
return {
assetCode: trustline.assetCode,
issuer: trustline.address
};
}import { getTrustlineConfig } from './trustlines';
async function deployEscrow() {
const trustlineConfig = getTrustlineConfig('USDC');
const deployPayload = {
// ... other escrow fields
trustline: [
{
assetCode: trustlineConfig.assetCode,
issuer: trustlineConfig.issuer
}
]
};
// Deploy escrow...
}Stellar assets typically use 7 decimals. When working with amounts:
// Convert human-readable to Stellar amount
function toStellarAmount(amount: number, decimals: number = 7): string {
return (amount * Math.pow(10, decimals)).toString();
}
// Convert Stellar amount to human-readable
function fromStellarAmount(amount: string, decimals: number = 7): number {
return parseInt(amount) / Math.pow(10, decimals);
}
// Example
const humanAmount = 100.50; // USDC
const stellarAmount = toStellarAmount(humanAmount); // "1005000000"
const backToHuman = fromStellarAmount(stellarAmount); // 100.50When specifying amounts in escrow deployment:
// For USDC with 7 decimals
const amount = 5000; // $5000 USD
const stellarAmount = 5000; // API handles conversion, or use raw: 50000000000
const escrowPayload = {
amount: stellarAmount, // or amount if API handles conversion
// ...
};import { Server } from 'stellar-sdk';
async function checkTrustline(accountAddress: string, assetCode: string, issuer: string) {
const server = new Server('https://horizon.stellar.org');
const account = await server.loadAccount(accountAddress);
const trustline = account.balances.find(
balance => balance.asset_code === assetCode && balance.asset_issuer === issuer
);
return {
exists: !!trustline,
balance: trustline?.balance || '0',
limit: trustline?.limit || '0'
};
}- Cause: Account doesn't have trustline for the asset
- Solution: Establish trustline before attempting to receive/hold asset
- Cause: Account doesn't have enough XLM for trustline reserve (0.5 XLM)
- Solution: Fund account with at least 0.5 XLM + transaction fees
- Cause: Wrong asset code or issuer address
- Solution: Verify asset code and issuer match exactly
- Establish trustlines early: Set up trustlines before escrow deployment
- Verify trustlines: Check that all parties have required trustlines
- Use constants: Store trustline configs in constants file
- Handle decimals: Always account for asset decimals when calculating amounts
- Test on testnet: Verify trustline setup on Stellar testnet first
- Document assets: Keep a list of supported assets and their configurations
// trustlines.ts
export const SUPPORTED_ASSETS = {
USDC: {
assetCode: 'USDC',
issuer: 'CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA',
decimals: 7,
name: 'USD Coin'
},
EURC: {
assetCode: 'EURC',
issuer: 'GB3Q6QDZYTHWT7E5PVS3W7FUT5GVAFC5KSZFFLPU25GO7VTC3NM2ZTVO',
decimals: 7,
name: 'Euro Coin'
}
};
export function getTrustlineForEscrow(assetCode: keyof typeof SUPPORTED_ASSETS) {
const asset = SUPPORTED_ASSETS[assetCode];
return {
assetCode: asset.assetCode,
issuer: asset.issuer
};
}
// Usage
const trustline = getTrustlineForEscrow('USDC');
// { assetCode: 'USDC', issuer: 'CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA' }