> ## 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.

# Deleverage Multiply Position with xStocks

> Reduce leverage by selling collateral to repay debt atomically

<p>Deleveraging a multiply position reduces your leverage by selling collateral to repay debt in a single atomic transaction. This operation uses flash loans and KSwap to convert TSLAx collateral into USDC to repay debt without requiring external funds.</p>

<Note>
  Multiply positions use `MultiplyObligation` which derives a unique PDA (Program Derived Address) based on your wallet, market, collateral token (TSLAx), and debt token (USDC). Each collateral/debt pair creates a separate obligation address, allowing you to have multiple multiply positions simultaneously.
</Note>

## Deleverage Multiply Position with xStocks

Reduce leverage on a TSLAx multiply position by selling collateral to repay USDC debt.

<Steps>
  <Step>
    ### Import Dependencies

    Import the required packages for Solana RPC communication, Kamino SDK operations, KSwap routing, Scope oracle, 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,
      getWithdrawWithLeverageIxs,
      getUserLutAddressAndSetupIxs,
      getScopeRefreshIxForObligationAndReserves,
      getComputeBudgetAndPriorityFeeIxs,
      lamportsToNumberDecimal,
      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, market, Scope oracle, and KSwap SDK.

    ```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

    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);
    ```
  </Step>

  <Step>
    ### Find TSLAx Reserve and Fetch Multiply LUTs

    Dynamically discover the TSLAx reserve and fetch multiply-specific lookup tables from Kamino's CDN.

    ```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');
    }
    const collTokenMint = tslaReserve.getLiquidityMint();

    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 = multiplyColPairs[debtTokenMint] || [];
    const multiplyLutKeys = multiplyLut.map((lut: string) => address(lut));
    ```
  </Step>

  <Step>
    ### Configure Deleverage Parameters

    Set the withdrawal amount and slippage tolerance.

    ```typescript theme={null}
    const withdrawAmount = new Decimal(3); // $3 worth to deleverage
    const slippageBps = 100; // 1% slippage (xStocks may need higher slippage)
    ```

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

  <Step>
    ### Get User Lookup Table

    Retrieve the user-specific lookup table created during the first multiply deposit.

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

    const [userLookupTable] = await getUserLutAddressAndSetupIxs(
      market!,
      signer,
      none(),
      true,
      multiplyMints,
      leverageMints
    );
    ```
  </Step>

  <Step>
    ### Fetch Multiply Obligation and Position Data

    Create the multiply obligation type, derive its PDA, and fetch current position data.

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

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

    if (!obligation) {
      console.log('No multiply obligation found. You must have an active multiply position to deleverage.');
    }

    const deposited = lamportsToNumberDecimal(
      Array.from(obligation.deposits.values())[0]?.amount.toString() || '0',
      collTokenReserve.state.liquidity.mintDecimals.toNumber()
    );
    const borrowed = lamportsToNumberDecimal(
      Array.from(obligation.borrows.values())[0]?.amount.toString() || '0',
      debtTokenReserve.state.liquidity.mintDecimals.toNumber()
    );

    console.log(`Current position: ${deposited.toString()} TSLAx deposited, ${borrowed.toString()} USDC borrowed`);
    ```

    <Info>
      The obligation PDA is derived from the market address, wallet address, collateral mint (TSLAx), and debt mint (USDC). This means a TSLAx/USDC multiply position has a different address than a NVDAx/USDC multiply position for the same wallet.
    </Info>
  </Step>

  <Step>
    ### Setup Scope Oracle and Price Data

    Get Scope oracle refresh instructions and price ratios for the swap.

    ```typescript theme={null}
    const scopeConfiguration = { scope, scopeConfigurations: await scope.getAllConfigurations() };
    const scopeRefreshIx = await getScopeRefreshIxForObligationAndReserves(
      market!,
      collTokenReserve,
      debtTokenReserve,
      obligation,
      scopeConfiguration
    );

    const collPriceUsd = collTokenReserve.getOracleMarketPrice();
    const debtPriceUsd = debtTokenReserve.getOracleMarketPrice();
    const priceCollToDebt = collPriceUsd.div(debtPriceUsd);
    ```
  </Step>

  <Step>
    ### Build Deleverage Instructions with Multiple Routes

    Set compute budget and build withdrawal with leverage instructions using KSwap for multi-route optimization.

    ```typescript theme={null}
    const computeIxs = getComputeBudgetAndPriorityFeeIxs(1_400_000, new Decimal(500000));

    const userSolBalanceLamports = Number.parseInt(
      (await rpc.getBalance(signer.address).send()).value.toString()
    );

    const withdrawWithLeverageRoutes = await getWithdrawWithLeverageIxs({
      owner: signer,
      kaminoMarket: market!,
      debtTokenMint: debtTokenMint,
      collTokenMint: collTokenMint,
      obligation: obligation,
      deposited: deposited,
      borrowed: borrowed,
      referrer: none(),
      currentSlot,
      withdrawAmount,
      priceCollToDebt,
      slippagePct: new Decimal(slippageBps / 100),
      isClosingPosition: false, // Set to true to close the entire position
      selectedTokenMint: debtTokenMint, // Withdraw into USDC
      budgetAndPriorityFeeIxs: computeIxs,
      scopeRefreshIx,
      quoteBufferBps: new Decimal(1000),
      quoter: getKswapQuoter(kswapSdk, signer.address, slippageBps, collTokenReserve, debtTokenReserve),
      swapper: getKswapSwapper(kswapSdk, signer.address, slippageBps),
      useV2Ixs: true,
      userSolBalanceLamports,
    });
    ```

    <Info>
      `getWithdrawWithLeverageIxs` handles the complex flow: flash borrow debt token → repay debt → withdraw freed collateral → swap collateral to debt token → repay flash loan. All in one atomic transaction.
    </Info>
  </Step>

  <Step>
    ### Simulate Routes and Select Best

    Prepare lookup tables, simulate all routes, and select the best performing route based on price.

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

    const klendLutAccounts = await fetchAllAddressLookupTable(rpc, klendLookupTableKeys);

    const simulationResults = await Promise.all(
      withdrawWithLeverageRoutes.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);

    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 = withdrawWithLeverageRoutes[0].lookupTables;
            lookupTables.push(...klendLutAccounts);
            return { ixs: withdrawWithLeverageRoutes[0].ixs, luts: lookupTables.map((l) => l.address) };
          })();

    if (!bestRoute) {
      console.log('No route found');
    }
    ```

    <Info>
      Simulation-based route selection ensures the transaction will succeed before sending it. Routes that fail simulation are filtered out, and the best price among passing routes is selected.
    </Info>
  </Step>

  <Step>
    ### Build, Sign, and Send Transaction

    Wait briefly to avoid rate limiting, get a fresh blockhash, compress the transaction with LUTs, and send it.

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

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

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

    const transactionMessage = pipe(
      createTransactionMessage({ version: 0 }),
      (tx) => appendTransactionMessageInstructions(bestRoute.ixs, tx),
      (tx) => setTransactionMessageFeePayerSigner(signer, tx),
      (tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),
      (tx) => compressTransactionMessageUsingAddressLookupTables(tx, lutsByAddress)
    );

    const signedTransaction = await signTransactionMessageWithSigners(transactionMessage);
    const signature = getSignatureFromTransaction(signedTransaction);

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

    console.log(`Multiply deleverage successful! Sold ~$${withdrawAmount.toString()} of collateral to repay debt.`);
    console.log(`Transaction signature: ${signature}`);
    ```

    <Check>
      The deleverage transaction is complete. Your leverage is reduced, debt is partially repaid, and remaining value is available as USDC or collateral based on the `selectedTokenMint` parameter.
    </Check>
  </Step>
</Steps>

### 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>
