All skills

DeFindex SDK

Community builtSKILL.md

Integrate DeFindex vaults on Stellar with the @defindex/sdk TypeScript package.

About

Use when integrating DeFindex vault operations on Stellar - depositing into vaults, withdrawing from vaults, checking balances, creating vaults, or submitting Soroban transactions using the @defindex/sdk TypeScript package.

Links
Tags
defindex-sdk · community · paltalabs
SKILL.md

DeFindex SDK Integration

Overview

The DeFindex SDK (@defindex/sdk) provides server-side TypeScript access to DeFindex vaults on Stellar/Soroban. The SDK returns unsigned XDR transactions that must be signed with @stellar/stellar-sdk before submission.

Core flow: Call SDK method -> receive unsigned XDR -> sign with Stellar keypair -> submit via sendTransaction().

When to Use

  • Building a backend or script that deposits/withdraws from DeFindex vaults
  • Querying vault balances, APY, or vault info
  • Creating new DeFindex vaults programmatically
  • Any server-side Stellar/Soroban interaction with the DeFindex protocol

Do NOT use for: Frontend wallet integrations where the user signs in-browser (use Freighter or other wallet adapters directly with the XDR).

Installation

pnpm add @defindex/sdk @stellar/stellar-sdk

SDK Setup

import DefindexSDK, { SupportedNetworks } from "@defindex/sdk";

const sdk = new DefindexSDK({
  apiKey: process.env.DEFINDEX_API_KEY as string, // Required for most operations
  baseUrl: "https://api.defindex.io",             // Optional, defaults to production
  timeout: 30000,                                  // Optional, ms
});

Networks: Use SupportedNetworks.TESTNET or SupportedNetworks.MAINNET.

Transaction Signing Pattern

Every transaction-building method (deposit, withdraw, create vault, etc.) returns a response containing an xdr field. This XDR is an unsigned Soroban transaction that must be:

  1. Parsed with TransactionBuilder.fromXDR()
  2. Cast as Transaction
  3. Signed with the caller's Keypair
  4. Serialized back to XDR with .toXDR()
  5. Submitted via sdk.sendTransaction()
import { Keypair, Networks, Transaction, TransactionBuilder } from "@stellar/stellar-sdk";

// After receiving a response with xdr from any SDK method:
const transaction = TransactionBuilder.fromXDR(response.xdr, Networks.TESTNET) as Transaction;
transaction.sign(callerKeypair);

const result = await sdk.sendTransaction(transaction.toXDR(), SupportedNetworks.TESTNET);

Use Networks.TESTNET or Networks.MAINNET from @stellar/stellar-sdk when parsing XDR.

Core Operations

Deposit into a Vault (Most Common)

Deposits assets into an existing vault. The amounts array corresponds to each asset the vault accepts, in stroops (1 XLM = 10,000,000 stroops, 1 USDC with 7 decimals = 10,000,000 stroops).

import DefindexSDK, { DepositParams, SupportedNetworks } from "@defindex/sdk";
import { Keypair, Networks, Transaction, TransactionBuilder } from "@stellar/stellar-sdk";

const callerKeypair = Keypair.fromSecret("S..._YOUR_SECRET_KEY");

const sdk = new DefindexSDK({
  apiKey: process.env.DEFINDEX_API_KEY as string,
  baseUrl: process.env.DEFINDEX_API_URL as string,
});

const vaultAddress = "CCJWW63WRWZASW7YIGWASHZVOKMDEKQ557CJOHRA5X3PG5KDPHWVITD5";

const depositParams: DepositParams = {
  amounts: [100000000],              // Amount per asset in stroops
  invest: false,                     // true = auto-invest into strategies after deposit
  caller: callerKeypair.publicKey(),
  // slippageBps?: 100,              // Optional: slippage tolerance in basis points (100 = 1%)
};

const depositResponse = await sdk.depositToVault(
  vaultAddress,
  depositParams,
  SupportedNetworks.TESTNET
);

// Sign and submit
const transaction = TransactionBuilder.fromXDR(
  depositResponse.xdr,
  Networks.TESTNET
) as Transaction;

transaction.sign(callerKeypair);

const result = await sdk.sendTransaction(
  transaction.toXDR(),
  SupportedNetworks.TESTNET
);

// result.success: boolean
// result.txHash: string
// result.result: { type: 'vault_deposit', sharesMinted: string }

Withdraw from a Vault (By Amount)

Withdraw specific amounts of each underlying asset.

import { WithdrawParams } from "@defindex/sdk";

const withdrawParams: WithdrawParams = {
  amounts: [50000000],               // Amount per asset to withdraw
  caller: callerKeypair.publicKey(),
  // slippageBps?: 100,
};

const withdrawResponse = await sdk.withdrawFromVault(
  vaultAddress,
  withdrawParams,
  SupportedNetworks.TESTNET
);

const tx = TransactionBuilder.fromXDR(withdrawResponse.xdr, Networks.TESTNET) as Transaction;
tx.sign(callerKeypair);
const result = await sdk.sendTransaction(tx.toXDR(), SupportedNetworks.TESTNET);
// result.result: { type: 'vault_withdraw', amountsOut: string[] }

Withdraw from a Vault (By Shares)

Withdraw by burning a number of vault share tokens instead of specifying asset amounts.

import { WithdrawSharesParams } from "@defindex/sdk";

const shareParams: WithdrawSharesParams = {
  shares: 1000000,                    // Number of vault shares to redeem
  caller: callerKeypair.publicKey(),
  // slippageBps?: 100,
};

const shareResponse = await sdk.withdrawShares(
  vaultAddress,
  shareParams,
  SupportedNetworks.TESTNET
);

const tx = TransactionBuilder.fromXDR(shareResponse.xdr, Networks.TESTNET) as Transaction;
tx.sign(callerKeypair);
await sdk.sendTransaction(tx.toXDR(), SupportedNetworks.TESTNET);

Check Vault Balance

Returns the user's vault shares (dfTokens) and the underlying asset values.

const balance = await sdk.getVaultBalance(
  vaultAddress,
  userPublicKey,          // Stellar public key (G...)
  SupportedNetworks.TESTNET
);

// balance.dfTokens: number       - User's vault share tokens
// balance.underlyingBalance: number[] - Value in each underlying asset

Get Vault Info

const info = await sdk.getVaultInfo(vaultAddress, SupportedNetworks.TESTNET);

// info.name: string
// info.symbol: string
// info.apy: number
// info.assets: VaultAsset[]       - Assets with their strategies
// info.totalManagedFunds: AssetManagedFunds[]
// info.feesBps: { vaultFee: number, defindexFee: number }
// info.roles: { manager, emergencyManager, rebalanceManager, feeReceiver }

Get Vault APY

const { apy } = await sdk.getVaultAPY(vaultAddress, SupportedNetworks.TESTNET);
// apy: number (percentage)

Vault Creation (One-Time Setup)

Create a Vault

import { CreateVaultParams } from "@defindex/sdk";

const vaultConfig: CreateVaultParams = {
  caller: managerKeypair.publicKey(),
  roles: {
    manager: managerKeypair.publicKey(),
    emergencyManager: "G...",
    rebalanceManager: "G...",
    feeReceiver: "G...",
  },
  vaultFeeBps: 100,                   // 1% fee (basis points, 0-10000)
  name: "My DeFi Vault",              // 1-32 chars
  symbol: "MDV",                      // 1-10 chars
  upgradable: true,
  assets: [{
    address: "C..._ASSET_CONTRACT",   // Soroban asset contract address
    strategies: [{
      address: "C..._STRATEGY_CONTRACT",
      name: "Strategy Name",
      paused: false,
    }],
  }],
};

const createResponse = await sdk.createVault(vaultConfig, SupportedNetworks.TESTNET);

const tx = TransactionBuilder.fromXDR(createResponse.xdr, Networks.TESTNET) as Transaction;
tx.sign(managerKeypair);
const result = await sdk.sendTransaction(tx.toXDR(), SupportedNetworks.TESTNET);
// result.result: { type: 'vault_create', vaultAddress: string }

Create Vault with Initial Deposit

Same as CreateVaultParams but adds depositAmounts:

import { CreateVaultDepositParams } from "@defindex/sdk";

const config: CreateVaultDepositParams = {
  ...vaultConfig,                     // Same as CreateVaultParams
  depositAmounts: [10000000],         // Initial deposit per asset
};

const response = await sdk.createVaultWithDeposit(config, SupportedNetworks.TESTNET);

Create Vault with Auto-Invest

Creates a vault, deposits, and invests into strategies atomically:

import { CreateVaultAutoInvestParams } from "@defindex/sdk";

const params: CreateVaultAutoInvestParams = {
  caller: callerKeypair.publicKey(),
  roles: { manager: "G...", emergencyManager: "G...", rebalanceManager: "G...", feeReceiver: "G..." },
  name: "Auto-Invest Vault",
  symbol: "AIV",
  vaultFee: 100,
  upgradable: true,
  assets: [{
    address: "C..._ASSET_CONTRACT",
    symbol: "XLM",
    amount: 10000000,                 // Total deposit amount
    strategies: [{
      address: "C..._STRATEGY_CONTRACT",
      name: "XLM Strategy",
      amount: 10000000,               // Amount to invest in this strategy
    }],
  }],
};

const response = await sdk.createVaultAutoInvest(params, SupportedNetworks.TESTNET);
// response.predictedVaultAddress: string - The predicted vault address
// response.warning?: string - Address prediction caveats

SendTransaction Response

All signed transactions are submitted via sendTransaction(). The response is:

interface SendTransactionResponse {
  txHash: string;                  // Stellar transaction hash
  success: boolean;                // Whether it succeeded
  result: TransactionResult | null;
  ledger: number;
  createdAt: string;               // ISO 8601
  feeBump: boolean;
  feeCharged: string;              // Fee in stroops
}

// result is a discriminated union:
type TransactionResult =
  | { type: 'vault_deposit'; sharesMinted: string }
  | { type: 'vault_withdraw'; amountsOut: string[] }
  | { type: 'vault_create'; vaultAddress: string }
  | { type: 'unknown'; value: unknown }

Quick Reference

OperationMethodReturns XDR?
DepositdepositToVault(vaultAddr, params, network)Yes
Withdraw (amount)withdrawFromVault(vaultAddr, params, network)Yes
Withdraw (shares)withdrawShares(vaultAddr, params, network)Yes
BalancegetVaultBalance(vaultAddr, userAddr, network)No (read-only)
Vault infogetVaultInfo(vaultAddr, network)No (read-only)
Vault APYgetVaultAPY(vaultAddr, network)No (read-only)
Create vaultcreateVault(config, network)Yes
Create + depositcreateVaultWithDeposit(config, network)Yes
Create + auto-investcreateVaultAutoInvest(params, network)Yes
Submit TXsendTransaction(signedXdr, network)N/A

Common Mistakes

Wrong network constant when parsing XDR: Use Networks.TESTNET (from @stellar/stellar-sdk) for XDR parsing but SupportedNetworks.TESTNET (from @defindex/sdk) for SDK method calls. They are different enums.

Forgetting to cast the parsed transaction: TransactionBuilder.fromXDR() returns a generic type. Always cast with as Transaction.

Amounts in wrong units: All amounts are in stroops (the smallest unit). For a 7-decimal token: 1 token = 10,000,000 stroops. For a 6-decimal token: 1 token = 1,000,000 stroops.

Missing API key: Most operations require an API key. Initialize the SDK with apiKey or authenticated calls will fail.

Not waiting before sendTransaction: After signing, a brief delay (~1s) before submitting can help avoid edge cases with Stellar's transaction queue.

Related skills