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:
- Parsed with
TransactionBuilder.fromXDR() - Cast as
Transaction - Signed with the caller's
Keypair - Serialized back to XDR with
.toXDR() - 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
| Operation | Method | Returns XDR? |
|---|---|---|
| Deposit | depositToVault(vaultAddr, params, network) | Yes |
| Withdraw (amount) | withdrawFromVault(vaultAddr, params, network) | Yes |
| Withdraw (shares) | withdrawShares(vaultAddr, params, network) | Yes |
| Balance | getVaultBalance(vaultAddr, userAddr, network) | No (read-only) |
| Vault info | getVaultInfo(vaultAddr, network) | No (read-only) |
| Vault APY | getVaultAPY(vaultAddr, network) | No (read-only) |
| Create vault | createVault(config, network) | Yes |
| Create + deposit | createVaultWithDeposit(config, network) | Yes |
| Create + auto-invest | createVaultAutoInvest(params, network) | Yes |
| Submit TX | sendTransaction(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.