> ## Documentation Index
> Fetch the complete documentation index at: https://docs.vanna.finance/llms.txt
> Use this file to discover all available pages before exploring further.

# Integrate Lending

> End-to-end guide for integrating Vanna's lending pools: supply liquidity, read pool state, and redeem vTokens.

This guide covers integrating Vanna's lending pools — depositing assets to earn yield, reading pool metrics, and redeeming vTokens.

***

## Overview

Vanna has four lending pools:

| Pool                    | Asset         | Supply to earn                  |
| ----------------------- | ------------- | ------------------------------- |
| LendingPoolXLM          | XLM           | Interest from XLM borrowers     |
| LendingPoolUSDC         | USDC          | Interest from USDC borrowers    |
| LendingPoolAquariusUSDC | Aquarius USDC | Interest from AQ USDC borrowers |
| LendingPoolSoroswapUSDC | Soroswap USDC | Interest from SO USDC borrowers |

Depositors receive **vTokens** (vXLM, vUSDC, etc.) that appreciate in value as interest accrues. Redeem them at any time for the underlying asset.

***

## Prerequisites

Set up the Stellar SDK and server connection — see [Getting Started](/developers/sdk/getting-started).

***

## Step 1: Read Pool State

Before depositing, read the pool's current metrics:

```typescript theme={null}
import { scValToNative, nativeToScVal } from '@stellar/stellar-sdk';

const POOL_XLM = 'CBA4E4ZMXUKCDTNT7LDKSO3LGNGKHRCE4GUVPSRCAKU3TKAONUY7SVOB';
const VXLM    = 'CCQAAPNBYF6I7PRM2NZ4NRDYZUVJJANMX3RZ4ZLMQH6Z5WAUL2MHU2RZ';
const WAD     = 10n ** 18n;

async function getPoolStats() {
  const [liquidityScVal, borrowsScVal] = await Promise.all([
    readContract(POOL_XLM, 'get_total_liquidity_in_pool'),
    readContract(POOL_XLM, 'get_borrows'),
  ]);

  const liquidityWad = liquidityScVal as bigint;
  const borrowsWad   = borrowsScVal as bigint;
  const totalAssets  = liquidityWad + borrowsWad;

  const utilizationRate = borrowsWad * WAD / totalAssets;
  // utilizationRate / WAD = 0.0 to 1.0

  // Get vToken exchange rate
  const vtokenSupplyScVal = await readContract(VXLM, 'total_supply');
  const vtokenSupply = vtokenSupplyScVal as bigint;

  const exchangeRate = totalAssets * WAD / vtokenSupply;
  // exchangeRate / WAD = underlying per vToken

  return {
    liquidityXlm: Number(liquidityWad) / 1e18,
    borrowsXlm:   Number(borrowsWad) / 1e18,
    utilization:  Number(utilizationRate) / 1e18, // 0.0 to 1.0
    exchangeRate: Number(exchangeRate) / 1e18,
  };
}
```

***

## Step 2: Get the Borrow APY

Query the Rate Model for the current borrow rate:

```typescript theme={null}
const RATE_MODEL = 'CCJAUPCU6EIFQK6GTAAYLW3Y4YETJAAUPAGBPFGQ2OUJPSW3WWHUCL2Z';
const SECS_PER_YEAR = 31_556_952n;

async function getBorrowAPY(liquidityWad: bigint, borrowsWad: bigint): Promise<number> {
  const ratePerSecWad = await readContract(
    RATE_MODEL,
    'get_borrow_rate_per_sec',
    [
      nativeToScVal(liquidityWad, { type: 'u256' }),
      nativeToScVal(borrowsWad,   { type: 'u256' }),
    ],
  ) as bigint;

  // Annual rate = rate_per_sec * SECS_PER_YEAR (in WAD)
  const annualRateWad = ratePerSecWad * SECS_PER_YEAR;
  return Number(annualRateWad) / 1e18; // 0.05 = 5% APY
}
```

The **supply APY** is approximately `borrow_APY × utilization_rate` (interest earned by LPs is the fraction of borrow interest from deployed capital).

***

## Step 3: Read a User's vToken Balance

```typescript theme={null}
async function getUserVtokenBalance(userAddress: string): Promise<bigint> {
  const balance = await readContract(
    VXLM,
    'balance',
    [nativeToScVal(userAddress, { type: 'address' })],
  ) as bigint;
  return balance;  // in i128, same scale as underlying
}

// Compute underlying value
async function getRedemptionValue(
  vtokenBalance: bigint,
  vtokenSupply: bigint,
  totalAssets: bigint,
): Promise<bigint> {
  return (vtokenBalance * totalAssets) / vtokenSupply;
}
```

***

## Step 4: Deposit (Supply Liquidity)

```typescript theme={null}
async function depositXlm(
  userAddress: string,
  amountXlm: number,  // human-readable (e.g., 10 for 10 XLM)
): Promise<string> {
  const WAD = 10n ** 18n;
  const amountWad = BigInt(Math.floor(amountXlm * 1e18));  // convert to WAD

  return await invokeContract(
    userAddress,
    POOL_XLM,
    'deposit_xlm',
    [
      nativeToScVal(userAddress, { type: 'address' }),
      nativeToScVal(amountWad,   { type: 'u256' }),
    ],
  );
}
```

<Note>
  The LendingPool transfers XLM from the caller's account. Freighter will prompt the user to authorize the native XLM transfer during the signing step — no separate `approve()` needed for XLM. For USDC pools, the `approve()` pattern is required.
</Note>

***

## Step 5: Redeem vTokens (Withdraw)

```typescript theme={null}
async function redeemVxlm(
  userAddress: string,
  vtokensToRedeem: bigint,  // in i128 (from balance() call)
): Promise<string> {
  return await invokeContract(
    userAddress,
    POOL_XLM,
    'redeem_vxlm',
    [
      nativeToScVal(userAddress,     { type: 'address' }),
      nativeToScVal(vtokensToRedeem, { type: 'u256' }),
    ],
  );
}
```

**To withdraw all:** fetch the user's vToken balance and pass it as `vtokensToRedeem`.

***

## Step 6: Fetch Deposit/Withdrawal History

Use Mercury to fetch historical events:

```typescript theme={null}
async function getEarnHistory(userAddress: string) {
  // Fetch deposit events where topic2 = user address
  const events = await fetchContractEvents(POOL_XLM, {
    account: userAddress,
    limit: 50,
  });

  return events.map(e => {
    const name = decodeScVal(e.topic1) as string;
    const data = decodeScVal(e.data) as {
      lender: string;
      amount: bigint;
      timestamp: bigint;
      asset_symbol: string;
    };
    return {
      type: name === 'deposit_event' ? 'deposit' : 'withdraw',
      amount: Number(data.amount) / 1e18,
      timestamp: Number(data.timestamp),
      asset: data.asset_symbol,
      txHash: e.tx,
    };
  });
}
```

***

## Full Pool Data Component (React)

```typescript theme={null}
import { useQuery } from '@tanstack/react-query';

function usePoolData(poolAddress: string, vtokenAddress: string) {
  return useQuery({
    queryKey: ['pool-data', poolAddress],
    queryFn: async () => {
      const [liquidity, borrows, vtokenSupply] = await Promise.all([
        readContract(poolAddress, 'get_total_liquidity_in_pool') as Promise<bigint>,
        readContract(poolAddress, 'get_borrows') as Promise<bigint>,
        readContract(vtokenAddress, 'total_supply') as Promise<bigint>,
      ]);

      const totalAssets = liquidity + borrows;
      const utilizationRate = borrows * WAD / totalAssets;
      const exchangeRate = vtokenSupply > 0n ? totalAssets * WAD / vtokenSupply : WAD;

      return { liquidity, borrows, totalAssets, utilizationRate, exchangeRate };
    },
    staleTime: 5_000,  // 5 seconds — one ledger
  });
}
```

***

## Error Handling

| Error                     | Cause                               | Fix                                          |
| ------------------------- | ----------------------------------- | -------------------------------------------- |
| `InsufficientBalance`     | Caller doesn't have enough XLM/USDC | Check balance before calling                 |
| `InsufficientPoolBalance` | Pool can't cover withdrawal         | Pool is fully utilized; wait for repayments  |
| Simulation fails          | Contract panic                      | Decode the error code from `simResult.error` |

***

## Related

* [Lending Pools Reference](/developers/contracts/lending-pools) — full function reference
* [vTokens Reference](/developers/contracts/vtokens) — vToken balance and transfer
* [Transaction Flow](/developers/sdk/transaction-flow) — build/sign/submit pattern
* [Math Reference](/developers/math-reference) — exchange rate and APY formulas
