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

# Multiply Deposit with KSwap

> Leverage your position by borrowing and swapping to deposit more collateral

<p>A multiply deposit creates a leveraged collateral position in a single, atomic transaction by combining an initial deposit with temporary liquidity.</p>

<p>When a multiply deposit is initiated, the protocol first temporarily borrows the debt token (for example, USDC) through a flash loan. The borrowed amount is swapped into the collateral token (for example, TSLAx) using KSwap (Kamino's token swap SDK). The resulting collateral is then deposited into Kamino Lend. With the collateral in place, the position borrows the debt token against it, and the borrowed amount is used to repay the flash loan before the transaction completes. The result is a leveraged position with increased exposure to the collateral token and an outstanding debt balance.</p>

## Multiply Deposit with xStocks

Create a leveraged position in a single atomic transaction using Klend's multiply feature and KSwap multi-route swap optimization.

<Steps>
  <Step>
    ### Import Dependencies

    Import the required packages for Solana RPC communication, Kamino SDK operations, KSwap routing, and transaction building.

    ```typescript theme={null}
    import {
      createSolanaRpc,
      createSolanaRpcSubscriptions,
      address,
      pipe,
      createTransactionMessage,
      setTransactionMessageFeePayerSigner,
      setTransactionMessageLifetimeUsingBlockhash,
      appendTransactionMessageInstructions,
      signTransactionMessageWithSigners,
      sendAndConfirmTransactionFactory,
      getSignatureFromTransaction,
      none,
      compressTransactionMessageUsingAddressLookupTables,
    } from '@solana/kit';
    import type { Address } from '@solana/kit';
    import {
      KaminoMarket,
      MultiplyObligation,
      PROGRAM_ID,
      parseKeypairFile,
      getDepositWithLeverageIxs,
      getUserLutAddressAndSetupIxs,
      getScopeRefreshIxForObligationAndReserves,
      getComputeBudgetAndPriorityFeeIxs,
      ObligationTypeTag,
      simulateTx,
      DEFAULT_RECENT_SLOT_DURATION_MS,
    } from '@kamino-finance/klend-sdk';
    import { KswapSdk } from '@kamino-finance/kswap-sdk';
    import { Scope } from '@kamino-finance/scope-sdk';
    import Decimal from 'decimal.js';
    import { getKswapQuoter, getKswapSwapper } from './kswap_utils.js';
    import { fetchAllAddressLookupTable } from '@solana-program/address-lookup-table';
    ```
  </Step>

  <Step>
    ### Load Configuration and Initialize SDKs

    Load the keypair and initialize RPC connections, the market, Scope for oracle prices, and KSwap for routing.

    ```typescript theme={null}
    const KEYPAIR_FILE = '/path/to/your/keypair.json';
    const CDN_ENDPOINT = 'https://cdn.kamino.finance';

    const signer = await parseKeypairFile(KEYPAIR_FILE);

    const rpc = createSolanaRpc('https://api.mainnet-beta.solana.com');
    const rpcSubscriptions = createSolanaRpcSubscriptions('wss://api.mainnet-beta.solana.com');

    const marketPubkey = address('5wJeMrUYECGq41fxRESKALVcHnNX26TAWy4W98yULsua'); // xStocks Market
    const debtTokenMint = address('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'); // USDC
    const XSTOCKS_MARKET_LUT = address('8ofreL6hKfEet1DnhHVGvCTnSdz4pg85PpbuCUHnEcKm'); // xStocks Market LUT

    let collTokenMint: Address;

    const market = await KaminoMarket.load(rpc, marketPubkey, DEFAULT_RECENT_SLOT_DURATION_MS);
    const scope = new Scope('mainnet-beta', rpc);
    const kswapSdk = new KswapSdk('https://api.kamino.finance/kswap', rpc, rpcSubscriptions);
    ```

    <Note>
      The xStocks Market LUT can be found via the Markets API: `https://api.kamino.finance/v2/kamino-market?programId=KLend2g3cP87fffoy8q1mQqGKjrxjC8boSyAYavgmjD`. The Scope SDK provides oracle price data, and the KSwap SDK enables multi-DEX routing for optimal swap execution.
    </Note>
  </Step>

  <Step>
    ### Find TSLAx Reserve in Market

    Dynamically discover the TSLAx token mint by searching the market reserves by symbol.

    ```typescript theme={null}
    const tslaReserve = Array.from(market!.reserves.values()).find((reserve) => reserve.symbol === 'TSLAx');
    if (!tslaReserve) {
      console.log('TSLAx reserve not found in xStocks market');
    }
    collTokenMint = tslaReserve.getLiquidityMint();
    console.log(`Found TSLAx mint: ${collTokenMint}`);
    ```

    <Info>
      This dynamic discovery approach allows the code to work across different markets without hardcoding token mint addresses. The reserve symbol identifies the asset (TSLAx for tokenized Tesla stock), and we retrieve its mint address programmatically.
    </Info>
  </Step>

  <Step>
    ### Fetch Multiply Lookup Tables

    Fetch multiply-specific Address Lookup Tables (LUTs) from Kamino's CDN for the TSLAx/USDC pair to compress transaction size.

    ```typescript theme={null}
    const kaminoResourcesResponse = await fetch(`${CDN_ENDPOINT}/resources.json`);
    const kaminoResourcesData = await kaminoResourcesResponse.json();
    const kaminoResources = kaminoResourcesData['mainnet-beta'];
    const multiplyColPairs = kaminoResources.multiplyLUTsPairs[collTokenMint] || {};
    const multiplyLut: string[] = multiplyColPairs[debtTokenMint] || [];
    const multiplyLutKeys = multiplyLut.map((lut) => address(lut));
    ```

    <Info>
      Lookup Tables store frequently-used addresses, allowing transactions to reference 1-byte indexes instead of 32-byte addresses. This reduces transaction size from \~3096 bytes to under 1232 bytes, which is critical for complex multiply operations.
    </Info>
  </Step>

  <Step>
    ### Configure Multiply Parameters

    Set the deposit amount, leverage multiplier, and slippage tolerance.

    ```typescript theme={null}
    const depositAmount = new Decimal(10); // $10 USDC
    const leverage = 2; // 2x leverage
    const slippageBps = 100; // 1% slippage
    ```

    <Note>
      Some assets may require higher slippage than others.
    </Note>
  </Step>

  <Step>
    ### Setup User Lookup Table

    Generate setup instructions for creating or extending a user-specific lookup table with addresses needed for multiply operations.

    ```typescript theme={null}
    const multiplyMints: { coll: Address; debt: Address }[] = [{ coll: collTokenMint, debt: debtTokenMint }];
    const leverageMints: { coll: Address; debt: Address }[] = [];

    const [userLookupTable, setupTxsIxs] = await getUserLutAddressAndSetupIxs(
      market!,
      signer,
      none(),
      true,
      multiplyMints,
      leverageMints
    );
    ```

    Execute the setup transactions if any are needed. The loop builds, signs, and sends each setup transaction, waiting 2 seconds between each to ensure proper ordering.

    ```typescript theme={null}
    for (const setupIxs of setupTxsIxs) {
      const { value: setupBlockhash } = await rpc.getLatestBlockhash({ commitment: 'finalized' }).send();

      const setupTx = pipe(
        createTransactionMessage({ version: 0 }),
        (tx) => setTransactionMessageFeePayerSigner(signer, tx),
        (tx) => setTransactionMessageLifetimeUsingBlockhash(setupBlockhash, tx),
        (tx) => appendTransactionMessageInstructions(setupIxs, tx)
      );

      const signedSetupTx = await signTransactionMessageWithSigners(setupTx);

      await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })(signedSetupTx, {
        commitment: 'confirmed',
        skipPreflight: true,
      });

      await new Promise((resolve) => setTimeout(resolve, 2000));
    }
    ```

    <Note>
      Setup transactions extend the lookup table with addresses specific to the multiply position. This is a one-time operation per collateral/debt pair - if the LUT already exists, `setupTxsIxs` will be empty and the loop won't execute.
    </Note>
  </Step>

  <Step>
    ### Check for Existing Obligation

    Check if a multiply obligation already exists for this collateral/debt pair.

    ```typescript theme={null}
    const currentSlot = await rpc.getSlot().send();
    const collTokenReserve = market!.getReserveByMint(collTokenMint)!;
    const debtTokenReserve = market!.getReserveByMint(debtTokenMint)!;

    const obligationAddress = await new MultiplyObligation(collTokenMint, debtTokenMint, PROGRAM_ID).toPda(
      market!.getAddress(),
      signer.address
    );
    const obligation = await market!.getObligationByAddress(obligationAddress);
    ```

    <Info>
      If an obligation exists, the transaction will add to the existing position. If `null`, a new obligation will be created using a flash loan to bootstrap the position.
    </Info>
  </Step>

  <Step>
    ### Get Scope Price Refresh Instructions

    Fetch latest oracle prices for accurate collateral and debt valuation.

    ```typescript theme={null}
    const scopeConfiguration = { scope, scopeConfigurations: await scope.getAllConfigurations() };

    const scopeRefreshIx = await getScopeRefreshIxForObligationAndReserves(
      market!,
      collTokenReserve,
      debtTokenReserve,
      obligation!,
      scopeConfiguration
    );
    ```
  </Step>

  <Step>
    ### Get Price from Scope Oracle and Build Routes

    Fetch the latest USDC/TSLAx price ratio from the Scope oracle (already loaded in reserves). Set the transaction compute budget and priority fee for reliable execution. Then use KSwap to generate multiple swap route options with the quoter and swapper helper functions. See the Helper Functions section below for the implementation of these utilities.

    ```typescript theme={null}
    // Get price ratio from Scope oracle (already loaded in reserves)
    const debtPriceUsd = debtTokenReserve.getOracleMarketPrice();
    const collPriceUsd = collTokenReserve.getOracleMarketPrice();
    const priceDebtToColl = debtPriceUsd.div(collPriceUsd);

    const computeIxs = getComputeBudgetAndPriorityFeeIxs(1_400_000, new Decimal(500000));

    const depositWithLeverageRoutes = await getDepositWithLeverageIxs({
      owner: signer,
      kaminoMarket: market!,
      debtTokenMint: debtTokenMint,
      collTokenMint: collTokenMint,
      depositAmount: depositAmount,
      priceDebtToColl: priceDebtToColl,
      slippagePct: new Decimal(slippageBps / 100),
      obligation: obligation || null,
      referrer: none(),
      currentSlot,
      targetLeverage: new Decimal(leverage),
      selectedTokenMint: debtTokenMint,
      obligationTypeTagOverride: ObligationTypeTag.Multiply,
      scopeRefreshIx,
      budgetAndPriorityFeeIxs: computeIxs,
      quoteBufferBps: new Decimal(1000),
      quoter: getKswapQuoter(kswapSdk, signer.address, slippageBps, debtTokenReserve, collTokenReserve),
      swapper: getKswapSwapper(kswapSdk, signer.address, slippageBps),
      useV2Ixs: true,
    });
    ```

    <Info>
      Using Scope oracle prices (`getOracleMarketPrice()`) is more reliable than external price APIs because Scope aggregates multiple oracle sources and is the same price feed used by Kamino Lend for position health calculations.
    </Info>
  </Step>

  <Step>
    ### Simulate Routes and Select Best

    Prepare the Klend lookup tables for transaction compression, then simulate all routes to find the best one that will succeed on-chain.

    ```typescript theme={null}
    const klendLookupTableKeys: Address[] = [];
    klendLookupTableKeys.push(userLookupTable);
    klendLookupTableKeys.push(...multiplyLutKeys);
    klendLookupTableKeys.push(XSTOCKS_MARKET_LUT);

    const klendLutAccounts = await fetchAllAddressLookupTable(rpc, klendLookupTableKeys);

    // Simulate all routes to find the best one
    const simulationResults = await Promise.all(
      depositWithLeverageRoutes.map(async (route) => {
        const lookupTables = route.lookupTables;
        lookupTables.push(...klendLutAccounts);

        const simulation = await simulateTx(rpc, signer.address, route.ixs, lookupTables).catch(() => undefined);

        if (!simulation || simulation.value.err) {
          return undefined;
        }

        return {
          ixs: route.ixs,
          luts: lookupTables.map((l) => l.address),
          routeOutput: route.quote!,
          swapInputs: route.swapInputs,
        };
      })
    );

    const passingSimulations = simulationResults.filter((tx) => tx !== undefined);

    // If no simulations pass, use first route anyway
    const bestRoute =
      passingSimulations.length > 0
        ? passingSimulations.reduce((best, current) => {
            const inputMintReserve = market!.getReserveByMint(best.swapInputs.inputMint)!;
            const outputMintReserve = market!.getReserveByMint(best.swapInputs.outputMint)!;

            const bestPrice = new Decimal(best.routeOutput.amountsExactIn.amountOutGuaranteed.toString())
              .div(outputMintReserve.getMintFactor())
              .div(new Decimal(best.routeOutput.amountsExactIn.amountIn.toString()).div(inputMintReserve.getMintFactor()));

            const currentPrice = new Decimal(current.routeOutput.amountsExactIn.amountOutGuaranteed.toString())
              .div(outputMintReserve.getMintFactor())
              .div(
                new Decimal(current.routeOutput.amountsExactIn.amountIn.toString()).div(inputMintReserve.getMintFactor())
              );

            return bestPrice.greaterThan(currentPrice) ? best : current;
          })
        : (() => {
            const lookupTables = [...depositWithLeverageRoutes[0].lookupTables, ...klendLutAccounts];
            return { ixs: depositWithLeverageRoutes[0].ixs, luts: lookupTables.map((l) => l.address) };
          })();

    if (!bestRoute) {
      throw new Error('No route found');
    }
    ```

    <Info>
      Simulation-based route selection tests each route on-chain before execution to ensure it will succeed. Routes that fail simulation are filtered out, and the best passing route is selected by price. If no routes pass simulation, the first route is used as a fallback.
    </Info>
  </Step>

  <Step>
    ### Build and Send Transaction

    Fetch a fresh blockhash, prepare lookup tables, and send the transaction.

    ```typescript theme={null}
    await new Promise((resolve) => setTimeout(resolve, 2000));

    const { value: latestBlockhash } = await rpc.getLatestBlockhash({ commitment: 'finalized' }).send();

    // Prepare LUT addresses for compression
    const lutsByAddress: Record<Address, Address[]> = {};
    const bestRouteLutAccounts = await fetchAllAddressLookupTable(rpc, bestRoute.luts || []);
    for (const acc of bestRouteLutAccounts) {
      lutsByAddress[acc.address] = acc.data.addresses;
    }

    // Build transaction using functional pipe pattern with LUT compression
    const transactionMessage = pipe(
      createTransactionMessage({ version: 0 }),
      (tx) => appendTransactionMessageInstructions(bestRoute.ixs, tx),
      (tx) => setTransactionMessageFeePayerSigner(signer, tx),
      (tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),
      (tx) => compressTransactionMessageUsingAddressLookupTables(tx, lutsByAddress)
    );

    // Sign transaction
    const signedTransaction = await signTransactionMessageWithSigners(transactionMessage);

    // Send and confirm transaction
    const signature = getSignatureFromTransaction(signedTransaction);

    await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })(signedTransaction, {
      commitment: 'processed',
      preflightCommitment: 'processed',
      skipPreflight: true,
    });

    console.log(`Multiply deposit successful! Signature: ${signature}`);
    ```

    <Check>
      The multiply deposit transaction is complete, resulting in a leveraged position with 2x exposure to TSLAx, all executed atomically in a single transaction.
    </Check>
  </Step>
</Steps>

## Helper Functions

The tutorial requires KSwap helper functions for price fetching and route building.

<AccordionGroup>
  <Accordion title="kswap_utils.ts">
    ```typescript theme={null}
    import BN from 'bn.js';
    import { KaminoReserve } from '@kamino-finance/klend-sdk';
    import type { SwapInputs, SwapQuote, SwapIxs, SwapIxsProvider, SwapQuoteProvider } from '@kamino-finance/klend-sdk';
    import { KswapSdk } from '@kamino-finance/kswap-sdk';
    import type { RouteOutput, RouteParams, RouterType } from '@kamino-finance/kswap-sdk';
    import Decimal from 'decimal.js';
    import type { Address } from '@solana/kit';

    const ALLOWED_ROUTERS: RouterType[] = ['dflow', 'jupiter', 'jupiterU', 'okx', 'jupiterLite'];

    export function getKswapQuoter(
      kswapSdk: KswapSdk,
      executor: Address,
      slippageBps: number,
      inputMintReserve: KaminoReserve,
      outputMintReserve: KaminoReserve
    ): SwapQuoteProvider<RouteOutput> {
      const quoter: SwapQuoteProvider<RouteOutput> = async (inputs: SwapInputs): Promise<SwapQuote<RouteOutput>> => {
        const routeParams: RouteParams = {
          executor: executor,
          tokenIn: inputs.inputMint,
          tokenOut: inputs.outputMint,
          amount: new BN(inputs.inputAmountLamports.toDP(0).toString()),
          maxSlippageBps: slippageBps,
          wrapAndUnwrapSol: false,
          swapType: 'exactIn',
          routerTypes: ALLOWED_ROUTERS,
          includeRfq: false,
          includeLimoLogs: false,
        };

        const routeOutputs = await kswapSdk.getAllRoutes(routeParams);

        if (routeOutputs.routes.length === 0) {
          throw new Error('No routes found from KSwap. Try increasing preferredMaxAccount.');
        }

        const bestRoute = routeOutputs.routes.reduce((best, current) => {
          const inAmountBest = new Decimal(best.amountsExactIn.amountIn.toString()).div(inputMintReserve.getMintFactor());
          const minAmountOutBest = new Decimal(best.amountsExactIn.amountOutGuaranteed.toString()).div(
            outputMintReserve.getMintFactor()
          );
          const priceAInBBest = minAmountOutBest.div(inAmountBest);
          const inAmountCurrent = new Decimal(current.amountsExactIn.amountIn.toString()).div(
            inputMintReserve.getMintFactor()
          );
          const minAmountOutCurrent = new Decimal(current.amountsExactIn.amountOutGuaranteed.toString()).div(
            outputMintReserve.getMintFactor()
          );
          const priceAInBCurrent = minAmountOutCurrent.div(inAmountCurrent);
          return priceAInBBest.greaterThan(priceAInBCurrent) ? best : current;
        });

        const inAmountBest = new Decimal(bestRoute.amountsExactIn.amountIn.toString()).div(
          inputMintReserve.getMintFactor()
        );
        const minAmountOutBest = new Decimal(bestRoute.amountsExactIn.amountOutGuaranteed.toString()).div(
          outputMintReserve.getMintFactor()
        );
        const priceAInBBest = minAmountOutBest.div(inAmountBest);

        return {
          priceAInB: priceAInBBest,
          quoteResponse: bestRoute,
        };
      };

      return quoter;
    }

    export function getKswapSwapper(
      kswapSdk: KswapSdk,
      executor: Address,
      slippageBps: number
    ): SwapIxsProvider<RouteOutput> {
      const swapper: SwapIxsProvider<RouteOutput> = async (inputs: SwapInputs): Promise<Array<SwapIxs<RouteOutput>>> => {
        const routeParams: RouteParams = {
          executor: executor,
          tokenIn: inputs.inputMint,
          tokenOut: inputs.outputMint,
          amount: new BN(inputs.inputAmountLamports.toString()),
          maxSlippageBps: slippageBps,
          wrapAndUnwrapSol: false,
          swapType: 'exactIn',
          routerTypes: ALLOWED_ROUTERS,
          includeRfq: false,
          includeLimoLogs: false,
        };

        const routeOutputs = await kswapSdk.getAllRoutes(routeParams);

        if (routeOutputs.routes.length === 0) {
          throw new Error('No routes found from KSwap in swapper.');
        }

        return routeOutputs.routes.map((routeOutput) => {
          const inAmount = new Decimal(routeOutput.amountsExactIn.amountIn.toString()).div(
            new Decimal(10).pow(routeOutput.inputTokenDecimals!)
          );
          const minAmountOut = new Decimal(routeOutput.amountsExactIn.amountOutGuaranteed.toString()).div(
            new Decimal(10).pow(routeOutput.outputTokenDecimals!)
          );
          const priceAInB = minAmountOut.div(inAmount);

          // Aggregate all swap-related instructions
          const allSwapIxs = [
            ...(routeOutput.instructions?.createInAtaIxs || []),
            ...(routeOutput.instructions?.wrapSolIxs || []),
            ...(routeOutput.instructions?.swapIxs || []),
            ...(routeOutput.instructions?.unwrapSolIxs || []),
            ...(routeOutput.instructions?.createOutAtaIxs || []),
          ];

          return {
            preActionIxs: [],
            swapIxs: allSwapIxs,
            lookupTables: routeOutput.lookupTableAccounts || [],
            quote: {
              priceAInB: new Decimal(priceAInB),
              quoteResponse: routeOutput,
            },
          };
        });
      };

      return swapper;
    }
    ```
  </Accordion>
</AccordionGroup>

## Transaction Flow

<Accordion title="View Transaction Flow Diagram" icon="diagram-project">
  ```mermaid theme={null}
  graph TD
      A[Load Market & SDKs] --> B[Fetch Multiply LUTs]
      B --> C[Setup User LUT]
      C --> D[Check Existing Obligation]
      D --> E[Refresh Scope Prices]
      E --> F[Build Multi-Route Swaps]
      F --> G[Simulate All Routes]
      G --> H[Select Best Route]
      H --> I[Compress with LUTs]
      I --> J[Sign & Send Transaction]

      J --> K{Transaction Success?}
      K -->|Yes| L[Leveraged Position Created]
      K -->|No| M[Transaction Reverts]
  ```
</Accordion>

## Asset Flow

<Accordion title="2x Leveraged TSLAx Position: Step-by-Step" icon="lightbulb">
  <Steps titleSize="p">
    <Step title="Initial State">
      * Wallet: 10 USDC
      * Position: None
    </Step>

    <Step title="Flash Borrow">
      * Flash loan: 10 USDC (temporary)
      * Available: 20 USDC total
    </Step>

    <Step title="Swap & Deposit">
      * Swap 20 USDC to TSLAx via KSwap
      * Deposit TSLAx as collateral
    </Step>

    <Step title="Borrow & Repay">
      * Borrow 10 USDC against collateral
      * Repay 10 USDC flash loan
    </Step>

    <Step title="Final Position">
      * Collateral: TSLAx (\$20 value)
      * Debt: 10 USDC
      * Net Equity: 10 USDC
      * Leverage: 2x
    </Step>
  </Steps>
</Accordion>

## Key Concepts

<AccordionGroup>
  <Accordion title="Flash Loans" icon="bolt">
    Flash loans are uncollateralized loans that must be borrowed and repaid within the same transaction. They enable:

    * **Zero upfront capital**: Borrow large amounts without collateral
    * **Atomic execution**: All operations succeed or fail together
    * **Leverage creation**: Bootstrap leveraged positions in one transaction
    * **Risk-free**: Transaction reverts if flash loan cannot be repaid
  </Accordion>

  <Accordion title="Multiply Obligation Type" icon="layer-group">
    The `MultiplyObligation` is a specialized obligation type that:

    * **Defines position type**: Multiply vs Leverage vs Vanilla
    * **Derives unique address**: Via PDA using collateral/debt mints
    * **Supports multiple positions**: Create different obligations with same tokens using ID parameter
    * **Creates new obligation**: When none exists (indicated by `obligation: null`)
  </Accordion>

  <Accordion title="Lookup Tables (LUTs)" icon="table">
    Address Lookup Tables reduce transaction size by:

    * **Storing common addresses**: Frequently-used program accounts, reserves, oracles
    * **Index-based references**: 1-byte index instead of 32-byte address
    * **Transaction compression**: Enables complex transactions to fit within the 1232-byte limit
    * **Multiply-specific LUTs**: Fetched from Kamino CDN per collateral/debt pair
    * **Critical for complex txns**: Multiply operations wouldn't fit without LUTs
  </Accordion>

  <Accordion title="Transaction Simulation" icon="flask">
    Transaction simulation tests routes before execution by:

    * **Pre-validation**: Running the transaction on-chain without committing state
    * **Error detection**: Identifying routes that would fail due to slippage, insufficient liquidity, or account errors
    * **Best route selection**: Choosing the route with the best price among passing simulations
    * **Fallback strategy**: Using the first route if no simulations pass (edge case)
    * **Reliability improvement**: Reduces failed transactions and improves user experience
  </Accordion>

  <Accordion title="KSwap Multi-Route Optimization" icon="route">
    KSwap provides optimal swap execution through:

    * **Multi-DEX routing**: Tests routes across Jupiter, OKX, dFlow, and other DEX aggregators
    * **Price optimization**: Selects the route with the best guaranteed output amount
    * **Slippage protection**: Ensures minimum output amount within tolerance
    * **Automatic ATA creation**: Handles token account creation and SOL wrapping/unwrapping
  </Accordion>

  <Accordion title="Commitment Levels" icon="clock">
    Solana commitment levels affect confirmation speed:

    * **`processed`**: Fastest, used for sending (no false timeout errors)
    * **`confirmed`**: Medium speed, confirmed by majority of cluster stake
    * **`finalized`**: Slowest, used for blockhash (maximum security, \~32 blocks)
    * **Recommended**: Use `processed` for multiply transactions to avoid false errors
  </Accordion>
</AccordionGroup>

### Borrow and Multiply SDK Methods

<div className="text-sm">
  | Method                       | Operation                       | When to Use                                                                 |
  | ---------------------------- | ------------------------------- | --------------------------------------------------------------------------- |
  | `getDepositWithLeverageIxs`  | Open position or add collateral | Creating or adding to a leveraged position                                  |
  | `buildRepayTxns`             | Repay with wallet funds         | Reducing debt using USDC, SOL, etc. from wallet                             |
  | `buildWithdrawTxns`          | Withdraw collateral             | Withdrawing collateral after debt is repaid                                 |
  | `getWithdrawWithLeverageIxs` | Deleverage and withdraw         | Sell collateral to repay debt and receive remaining value in wallet         |
  | `getRepayWithCollIxs`        | Repay debt with collateral      | Sell collateral to repay debt without withdrawing (value stays in position) |

  <Note>
    **Multiply operations** use `MultiplyObligation`. **Vanilla operations** use `VanillaObligation`. The obligation type determines which PDA is derived for your position.
  </Note>
</div>

## Related Resources

<CardGroup cols={2}>
  <Card title="Deposit and Borrow" icon="coins" href="/docs/build/tutorials/borrow/deposit-and-borrow">
    Learn basic deposit and borrow operations
  </Card>

  <Card title="Market Data" icon="chart-line" href="/docs/build/developers/borrow/data/market-data">
    Read market metrics and reserve data
  </Card>

  <Card title="KSwap SDK" icon="code" href="https://www.npmjs.com/package/@kamino-finance/kswap-sdk">
    Multi-DEX swap routing SDK
  </Card>

  <Card title="Scope SDK" icon="globe" href="https://github.com/Kamino-Finance/scope-sdk">
    Oracle price aggregation SDK
  </Card>
</CardGroup>
