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

# Vault Swap

> Move a position from one vault to another atomically.

> [!NOTE]
>
> These flows use many instructions. If you hit compute limits, add `ComputeBudgetProgram.setComputeUnitLimit({ units: 1_000_000 })` (or higher) as the first instruction in your transaction.

> [!WARNING]
>
> Solana transactions have a 1232-byte size limit. If the serialised transaction exceeds 1232 bytes, the vault swap will not be possible in a single transaction. Consider splitting large positions or using simpler swap routes.

A vault swap moves your [borrow position](https://developers.jup.ag/docs/lend/borrow.md) from one vault to another atomically. Use Jupiter **Swap API** for swap quotes and instructions.

**Flow:** swap from SOL/USDC to SOL/USDT:

1. [Flashloan](https://developers.jup.ag/docs/lend/flashloan.md) USDC
2. Repay all USDC debt and withdraw all SOL from vault 1
3. [Deposit](https://developers.jup.ag/docs/lend/borrow/deposit.md) SOL into vault 2 and [borrow](https://developers.jup.ag/docs/lend/borrow/borrow.md) USDT with a 1-2 USD buffer for slippage
4. Swap the new debt token → USDC
5. Pay back the flashloan

***

## Vault Swap

## 1. Import Dependencies

```typescript theme={null}
import {
  AddressLookupTableAccount,
  Connection,
  Keypair,
  PublicKey,
  TransactionInstruction,
  TransactionMessage,
  VersionedTransaction,
} from "@solana/web3.js";
import BN from "bn.js";
import { getFlashBorrowIx, getFlashPaybackIx } from "@jup-ag/lend/flashloan";
import { getOperateIx, MAX_REPAY_AMOUNT, MAX_WITHDRAW_AMOUNT } from "@jup-ag/lend/borrow";
import fs from "fs";
import path from "path";
```

## 2. Set Parameters

Hardcode vault IDs, `positionId` (NFT ID in vault 1), `debtAmount`, `collateralSupply`, and a borrow buffer (e.g. 2 USDC) for slippage.

```typescript theme={null}
const KEYPAIR_PATH = "/path/to/your/keypair.json";
const RPC_URL = "https://api.mainnet-beta.solana.com";
function loadKeypair(p: string): Keypair {
  return Keypair.fromSecretKey(new Uint8Array(JSON.parse(fs.readFileSync(path.resolve(p), "utf8"))));
}
const userKeypair = loadKeypair(KEYPAIR_PATH);
const connection = new Connection(RPC_URL, { commitment: "confirmed" });
const signer = userKeypair.publicKey;

const usdcMint = new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");
const usdtMint = new PublicKey("Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB");

const VAULT_1_ID = 1; // SOL/USDC
const VAULT_2_ID = 2; // SOL/USDT
const positionId = 7360; // NFT ID of position in vault 1
const debtAmount = new BN(20_000_000); // USDC debt to repay (6 decimals)
const collateralSupply = new BN(1_000_000_000); // SOL to move (9 decimals)
const BORROW_BUFFER = new BN(2_000_000); // 2 USDC extra for slippage
const borrowAmount = debtAmount.add(BORROW_BUFFER);
```

## 3. Get Flashloan Instructions

Flashloan the **debt asset** of vault 1 (e.g. USDC).

```typescript theme={null}
const flashParams = { connection, signer, asset: usdcMint, amount: debtAmount };
const flashBorrowIx = await getFlashBorrowIx(flashParams);
const flashPaybackIx = await getFlashPaybackIx(flashParams);
```

## 4. Close Position in Vault 1 (Repay + Withdraw)

```typescript theme={null}
const { ixs: operate1Ixs, addressLookupTableAccounts: alts1 } = await getOperateIx({
  vaultId: VAULT_1_ID,
  positionId,
  colAmount: MAX_WITHDRAW_AMOUNT,
  debtAmount: MAX_REPAY_AMOUNT,
  connection,
  signer,
});
```

## 5. Open Position in Vault 2 (Deposit + Borrow)

Use `positionId: 0` for a new position. Deposit the withdrawn collateral and borrow the new debt token plus buffer.

```typescript theme={null}
const { ixs: operate2Ixs, addressLookupTableAccounts: alts2 } = await getOperateIx({
  vaultId: VAULT_2_ID,
  positionId: 0,
  colAmount: collateralSupply,
  debtAmount: borrowAmount,
  connection,
  signer,
});
```

## 6. Get Quote and Swap Instructions

Fetch a quote to swap the new debt token (e.g. USDT) → USDC. Ensure output is at least `debtAmount` to cover the flashloan.

```typescript theme={null}
const SWAP_API = "https://api.jup.ag/swap/v1";
const quoteResponse = await fetch(
  `${SWAP_API}/quote?inputMint=${usdtMint.toBase58()}&outputMint=${usdcMint.toBase58()}&amount=${borrowAmount.toString()}&slippageBps=100`,
  { headers: { "x-api-key": "your-api-key" } }
).then((r) => r.json());

const swapRes = await fetch(`${SWAP_API}/swap-instructions`, {
  method: "POST",
  headers: { "Content-Type": "application/json", "x-api-key": "your-api-key" },
  body: JSON.stringify({ quoteResponse, userPublicKey: signer.toBase58() }),
}).then((r) => r.json());
const swapIx = jupIxToTransactionInstruction(swapRes.swapInstruction);
```

The `jupIxToTransactionInstruction` helper converts the JSON instruction from the API into a Solana `TransactionInstruction`:

```typescript theme={null}
function jupIxToTransactionInstruction(ix: {
  programId: string;
  accounts: Array<{ pubkey: string; isSigner: boolean; isWritable: boolean }>;
  data: string;
}): TransactionInstruction {
  return new TransactionInstruction({
    programId: new PublicKey(ix.programId),
    keys: ix.accounts.map((a) => ({
      pubkey: new PublicKey(a.pubkey),
      isSigner: a.isSigner,
      isWritable: a.isWritable,
    })),
    data: Buffer.from(ix.data, "base64"),
  });
}
```

## 7. Assemble and Execute the Transaction

**Order:** Flashloan Borrow → Vault 1 Operate (repay + withdraw) → Vault 2 Operate (deposit + borrow) → Swap (new debt → USDC) → Flashloan Payback

The `getAddressLookupTableAccounts` helper resolves lookup table addresses into account objects:

```typescript theme={null}
async function getAddressLookupTableAccounts(
  connection: Connection,
  keys: string[]
): Promise<AddressLookupTableAccount[]> {
  if (!keys?.length) return [];
  const infos = await connection.getMultipleAccountsInfo(keys.map((k) => new PublicKey(k)));
  return infos.reduce((acc, info, i) => {
    if (info) {
      acc.push(new AddressLookupTableAccount({
        key: new PublicKey(keys[i]),
        state: AddressLookupTableAccount.deserialize(info.data),
      }));
    }
    return acc;
  }, [] as AddressLookupTableAccount[]);
}
```

```typescript theme={null}
const swapAlts = await getAddressLookupTableAccounts(connection, swapRes.addressLookupTableAddresses ?? []);
const allAlts = [...(alts1 ?? []), ...(alts2 ?? []), ...swapAlts];

const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash();
const message = new TransactionMessage({
  payerKey: signer,
  recentBlockhash: blockhash,
  instructions: [flashBorrowIx, ...operate1Ixs, ...operate2Ixs, swapIx, flashPaybackIx],
}).compileToV0Message(allAlts);

const tx = new VersionedTransaction(message);
tx.sign([userKeypair]);
const signature = await connection.sendTransaction(tx, { skipPreflight: false, maxRetries: 3 });
console.log("Vault swap successful:", signature);
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.