Skip to main content
This guide covers everything you need to start integrating with Vanna Protocol from a TypeScript/JavaScript environment — reading pool state, checking health factors, and executing margin operations.

Prerequisites


Installation

npm install @stellar/stellar-sdk @stellar/freighter-api
PackageVersionPurpose
@stellar/stellar-sdk^14.xSoroban contract calls, transaction building, XDR encoding
@stellar/freighter-api^6.xBrowser wallet connection and signing

Network Configuration

import { SorobanRpc, Networks } from '@stellar/stellar-sdk';

const NETWORK_PASSPHRASE = Networks.TESTNET;
// 'Test SDF Network ; September 2015'

const server = new SorobanRpc.Server(
  'https://soroban-testnet.stellar.org',
  { allowHttp: false }
);

Contract Addresses

All addresses are available in Deployed Contracts. Import them centrally:
export const CONTRACTS = {
  REGISTRY:        'CC35XWCH7SCQROTNW7PA6HZKP4JMNSVV2K7CX3HY2PSI2MI2ZQQH73ID',
  ORACLE:          'CB72D6SOUHUTCESXYOQOBMP6MRSH47NBYIBH73BBRH3ZRT53LPTB6R7V',
  RATE_MODEL:      'CCJAUPCU6EIFQK6GTAAYLW3Y4YETJAAUPAGBPFGQ2OUJPSW3WWHUCL2Z',
  RISK_ENGINE:     'CBL7RCG5H4VIZCNF7BRM2FQFXK7N5KRQKW7ZVEQZJKNXHA6FEU4OXK5I',
  ACCOUNT_MANAGER: 'CAK2IJIO2SKZWUODY4G7ZRIUUIIMJUUAIXE3I5YTQ5QYNSS2RYJ3P4CV',
  TRACKING_TOKEN:  'CA24GDWO63ZXNMW5FLWF2KMZ5DCF3DO7J3RYABFICDIDHH4A342RD2TR',

  // Lending pools
  POOL_XLM:        'CBA4E4ZMXUKCDTNT7LDKSO3LGNGKHRCE4GUVPSRCAKU3TKAONUY7SVOB',
  POOL_USDC:       'CABLEI2ZPCWLO2FQRHJJYR7JW75BCCPN2ZIV5BX7CHPXZT4CZVTGUOBU',

  // vTokens
  VXLM:            'CCQAAPNBYF6I7PRM2NZ4NRDYZUVJJANMX3RZ4ZLMQH6Z5WAUL2MHU2RZ',
  VUSDC:           'CDAJHQEJ26EBBGV2UYSR5S5LLA6F3A7KQISLPY5JMOL77RUDBEWG3T6Y',

  // Native tokens
  XLM_SAC:         'CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC',
  USDC:            'CAQCFVLOBK5GIULPNZRGATJJMIZL5BSP7X5YJVMGCPTUEPFM4AVSRCJU',
} as const;

Simulating (Reading) Contracts

For read-only operations, use server.simulateTransaction(). No signing required.
import {
  Contract,
  TransactionBuilder,
  Account,
  SorobanRpc,
  scValToNative,
  nativeToScVal,
  xdr,
} from '@stellar/stellar-sdk';

const NETWORK_PASSPHRASE = 'Test SDF Network ; September 2015';

async function simulateContractCall(
  contractAddress: string,
  method: string,
  args: xdr.ScVal[] = [],
): Promise<xdr.ScVal> {
  const contract = new Contract(contractAddress);
  const account = new Account('GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN', '0');

  const tx = new TransactionBuilder(account, {
    fee: '100',
    networkPassphrase: NETWORK_PASSPHRASE,
  })
    .addOperation(contract.call(method, ...args))
    .setTimeout(30)
    .build();

  const result = await server.simulateTransaction(tx);

  if (SorobanRpc.Api.isSimulationError(result)) {
    throw new Error(`Simulation failed: ${result.error}`);
  }

  return result.result!.retval;
}

Reading Pool State

// Get total borrows from the XLM pool
const borrowsScVal = await simulateContractCall(CONTRACTS.POOL_XLM, 'get_borrows');
const borrowsWad = scValToNative(borrowsScVal) as bigint;
// borrowsWad is in 10^18 scale. Divide by 10^7 for XLM (7 decimals), then by 10^11.

// Get total liquidity
const liquidityScVal = await simulateContractCall(CONTRACTS.POOL_XLM, 'get_total_liquidity_in_pool');
const liquidityWad = scValToNative(liquidityScVal) as bigint;

// Compute utilization
const WAD = 10n ** 18n;
const utilization = (borrowsWad * WAD) / (liquidityWad + borrowsWad);
// utilization is in WAD (10^18 = 100%)

Reading a User’s Margin Account

// Step 1: Find the user's SmartAccount via Registry
const accountsScVal = await simulateContractCall(
  CONTRACTS.REGISTRY,
  'get_accounts',
  [nativeToScVal(userWalletAddress, { type: 'address' })]
);
const accounts = scValToNative(accountsScVal) as string[];
const smartAccount = accounts[0]; // user's active margin account

// Step 2: Read health factor inputs
const collateralScVal = await simulateContractCall(
  CONTRACTS.RISK_ENGINE,
  'get_current_total_balance',
  [nativeToScVal(smartAccount, { type: 'address' })]
);
const collateralUsdWad = scValToNative(collateralScVal) as bigint;

const debtScVal = await simulateContractCall(
  CONTRACTS.RISK_ENGINE,
  'get_current_total_borrows',
  [nativeToScVal(smartAccount, { type: 'address' })]
);
const debtUsdWad = scValToNative(debtScVal) as bigint;

// Step 3: Compute health factor
const healthFactor = debtUsdWad > 0n
  ? (collateralUsdWad * WAD) / debtUsdWad
  : null; // no debt

Connecting a Freighter Wallet

import {
  requestAccess,
  getAddress,
  signTransaction,
} from '@stellar/freighter-api';

// Request wallet access (shows Freighter popup)
async function connectWallet(): Promise<string> {
  await requestAccess();
  const address = await getAddress();
  return address;
}

Executing Transactions

See Transaction Flow for the complete pattern: build → simulate → sign → submit.

Reading Oracle Prices

const priceScVal = await simulateContractCall(
  CONTRACTS.ORACLE,
  'get_price_latest',
  [nativeToScVal('XLM', { type: 'symbol' })]
);

const [price, decimals] = scValToNative(priceScVal) as [bigint, number];
// Convert to WAD: price_wad = price * (10^18 / 10^decimals)
const priceWad = price * (10n ** 18n) / (10n ** BigInt(decimals));

Handling Errors

Soroban errors from contract panics appear in simulation as SimulationError or in transaction results as invokeHostFunctionError. Parse them:
import { SorobanRpc } from '@stellar/stellar-sdk';

const result = await server.simulateTransaction(tx);

if (SorobanRpc.Api.isSimulationError(result)) {
  // Contract panicked or insufficient resources
  console.error('Simulation error:', result.error);
  throw new Error(result.error);
}

if (SorobanRpc.Api.isSimulationSuccess(result) && result.result?.auth) {
  // Check for auth errors — missing require_auth()
}
Common error patterns:
  • InsufficientBalance — caller doesn’t have enough tokens
  • InsufficientPoolBalance — pool can’t cover withdrawal
  • RiskEngineNotInitialized — missing registry setup
  • Health factor check failure — logged as a contract panic with specific error code

Next Steps

Transaction Flow

Build, simulate, sign, and submit Soroban transactions step by step.

Mercury Indexer

Query historical events and transaction history via the Mercury indexer.

Integrate Lending

End-to-end guide for deposit and vToken redemption.

Integrate Margin

Create accounts, deposit collateral, and borrow assets.