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

# Jupiter Swapping with Swig

# Swapping Tokens with Jupiter using Swig

This guide demonstrates how to perform token swaps on Solana using Jupiter Protocol with a Swig wallet. We'll create a simple example that swaps SOL for USDC using Jupiter's optimized routing.

## Prerequisites

Before you begin, make sure you have the following installed:

* [Bun](https://bun.sh) (latest version)
* A Solana wallet with some SOL for transaction fees (at least 0.02 SOL)
* A keypair file for the root user
* RPC\_URL environment variable set to your Solana RPC endpoint

## Setup

First, clone the swig-ts repository and navigate to the swap example:

```bash theme={null}
git clone https://github.com/anagrambuild/swig-ts.git
cd swig-ts/examples/swap
bun install
export RPC_URL="your-solana-rpc-url"
```

The example already includes all necessary dependencies:

* `@jup-ag/api` for Jupiter API integration
* `@swig-wallet/classic` for Swig wallet functionality
* `@solana/web3.js` for Solana interactions
* `@solana/spl-token` for token account management
* `chalk` for colorful console output

## Understanding the Code

The example demonstrates several key concepts:

1. Setting up Swig with proper compute budget handling
2. Managing token accounts (ATAs)
3. Using Jupiter's API for quotes and swap instructions
4. Properly separating and signing instructions
5. Using utility functions for common operations

### Utility Functions

The example includes several helper functions to simplify common operations:

```typescript theme={null}
// Helper function to send transactions
async function sendTransaction(
  connection: Connection,
  instructions: TransactionInstruction[],
  payer: Keypair,
): Promise<string> {
  const tx = new Transaction().add(...instructions);
  tx.feePayer = payer.publicKey;
  tx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
  tx.sign(payer);
  const sig = await connection.sendRawTransaction(tx.serialize());
  await connection.confirmTransaction(sig);
  return sig;
}

// Helper function to convert Jupiter instructions
function toTransactionInstruction(instruction: any): TransactionInstruction {
  return new TransactionInstruction({
    programId: new PublicKey(instruction.programId),
    keys: instruction.accounts.map((k: any) => ({
      pubkey: new PublicKey(k.pubkey),
      isSigner: k.isSigner,
      isWritable: k.isWritable,
    })),
    data: Buffer.from(instruction.data, 'base64'),
  });
}

// Helper function to format numbers with commas
function formatNumber(n: number) {
  return n.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
}

// Helper function to generate random bytes (for Swig ID)
function randomBytes(length: number): Uint8Array {
  const randomArray = new Uint8Array(length);
  crypto.getRandomValues(randomArray);
  return randomArray;
}
```

Let's break down the main components:

### 1. Creating and Getting the Swig Wallet Address

After creating your Swig account, you need to get the wallet address which is used for all transfers and token operations:

```typescript theme={null}
import {
  fetchSwig,
  findSwigPda,
  getSwigWalletAddress,
  getCreateSwigInstruction,
} from '@swig-wallet/classic';

// Create or find your Swig account
const id = randomBytes(32);
const swigAccountAddress = findSwigPda(id);

// Create the Swig (if new)
const createIx = await getCreateSwigInstruction({
  payer: rootUser.publicKey,
  actions: rootActions,
  authorityInfo: createEd25519AuthorityInfo(rootUser.publicKey),
  id,
});
await sendTransaction(connection, [createIx], rootUser);

// Fetch the Swig account and get the wallet address
const swig = await fetchSwig(connection, swigAccountAddress);
const swigWalletAddress = await getSwigWalletAddress(swig);
console.log('Swig wallet address:', swigWalletAddress.toBase58());
```

**Important**: Always use `swigWalletAddress` (not `swigAccountAddress`) for all transfer operations, token accounts, and Jupiter swaps.

### 2. Setting Up Token Accounts

<Note>
  Jupiter's returned setup instructions create any missing token accounts. The
  explicit setup below is useful when you want to create and inspect them first.
</Note>

Before swapping, we need to ensure the Swig wallet has the necessary token accounts (both USDC and Wrapped SOL):

```typescript theme={null}
const usdcMint = new PublicKey(
  'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
);
const wrappedSolMint = new PublicKey(
  'So11111111111111111111111111111111111111112',
);

// Check if Swig has USDC ATA
const swigUsdcAta = await getAssociatedTokenAddress(
  usdcMint,
  swigWalletAddress,
  true,
);
try {
  await getAccount(connection, swigUsdcAta);
  console.log(
    chalk.green('✓ USDC ATA exists:'),
    chalk.cyan(swigUsdcAta.toBase58()),
  );
} catch {
  const createAtaIx = createAssociatedTokenAccountInstruction(
    rootUser.publicKey,
    swigUsdcAta,
    swigWalletAddress,
    usdcMint,
  );
  await sendTransaction(connection, [createAtaIx], rootUser);
  console.log(
    chalk.green('✓ Created USDC ATA:'),
    chalk.cyan(swigUsdcAta.toBase58()),
  );
}

// Check if Swig has Wrapped SOL ATA
const swigWrappedSolAta = await getAssociatedTokenAddress(
  wrappedSolMint,
  swigWalletAddress,
  true,
);
try {
  await getAccount(connection, swigWrappedSolAta);
  console.log(
    chalk.green('✓ Wrapped SOL ATA exists:'),
    chalk.cyan(swigWrappedSolAta.toBase58()),
  );
} catch {
  const createAtaIx = createAssociatedTokenAccountInstruction(
    rootUser.publicKey,
    swigWrappedSolAta,
    swigWalletAddress,
    wrappedSolMint,
  );
  await sendTransaction(connection, [createAtaIx], rootUser);
  console.log(
    chalk.green('✓ Created Wrapped SOL ATA:'),
    chalk.cyan(swigWrappedSolAta.toBase58()),
  );
}
```

### 3. Getting Jupiter Quote

```typescript theme={null}
const transferAmount = 0.01 * LAMPORTS_PER_SOL;

const jupiter = createJupiterApiClient();
const quote = await jupiter.quoteGet({
  inputMint: wrappedSolMint.toBase58(),
  outputMint: usdcMint.toBase58(),
  amount: Math.floor(transferAmount),
  slippageBps: 50,
  maxAccounts: 64,
});

if (!quote) {
  console.log(chalk.red('❌ No quote available'));
  return;
}

console.log(chalk.blue('📊 Quote received:'));
console.log(`   Input: ${formatNumber(Number(quote.inAmount))} lamports`);
console.log(`   Output: ${formatNumber(Number(quote.outAmount))} USDC (raw)`);
```

### 4. Handling Compute Budget and Instructions

The most critical part is properly separating and handling instructions:

```typescript theme={null}
const swapInstructionsRes = await jupiter.swapInstructionsPost({
  swapRequest: {
    quoteResponse: quote,
    userPublicKey: swigWalletAddress.toBase58(),
    wrapAndUnwrapSol: true,
    useSharedAccounts: true,
  },
});

const swapInstructions: TransactionInstruction[] = [
  ...(swapInstructionsRes.setupInstructions || []).map(
    toTransactionInstruction,
  ),
  toTransactionInstruction(swapInstructionsRes.swapInstruction),
];

// Sign instructions with Swig
const rootRole = swig.findRolesByEd25519SignerPk(rootUser.publicKey)[0];
const signIxs = await getSignInstructions(
  swig,
  rootRole.id,
  swapInstructions,
);
```

### 5. Creating and Sending the Transaction

```typescript theme={null}
const lookupTables = await Promise.all(
  swapInstructionsRes.addressLookupTableAddresses.map(async (addr) => {
    const res = await connection.getAddressLookupTable(new PublicKey(addr));
    return res.value!;
  }),
);

const { blockhash, lastValidBlockHeight } =
  await connection.getLatestBlockhash();
const outerIxs = [
  ComputeBudgetProgram.setComputeUnitLimit({ units: 150_000 }),
  ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 50 }),
];

const messageV0 = new TransactionMessage({
  payerKey: rootUser.publicKey,
  recentBlockhash: blockhash,
  instructions: [...outerIxs, ...signIxs],
}).compileToV0Message(lookupTables);

const tx = new VersionedTransaction(messageV0);
tx.sign([rootUser]);

const signature = await connection.sendTransaction(tx, {
  skipPreflight: true,
  preflightCommitment: 'confirmed',
});

const result = await connection.confirmTransaction({
  signature,
  blockhash,
  lastValidBlockHeight,
});

if (result.value.err) {
  throw new Error(`Transaction failed: ${JSON.stringify(result.value.err)}`);
}

const postSwapBalance = await connection.getTokenAccountBalance(swigUsdcAta);
console.log(chalk.green('🎉 Swap successful!'));
console.log(chalk.gray(`   Signature: ${signature}`));
console.log(
  chalk.blue(`💰 New USDC balance: ${postSwapBalance.value.uiAmount}`),
);
```

## Important Considerations

1. **Compute Budget Management**:
   * Set appropriate compute unit limit and price
   * These instructions must be outside of Swig-signed instructions

2. **Account Management**:
   * Create ATAs in separate transactions before swapping
   * Account for Swig's overhead when setting `maxAccounts`

3. **Transaction Structure**:
   * Properly separate outer instructions from Swig-signed instructions
   * Use `getSignInstructions` to sign all Swig instructions at once
   * Use versioned transactions with address lookup tables

4. **Error Handling**:
   * Verify ATA existence and creation
   * Check transaction confirmation status
   * Verify token balances after swap

## Running the Example

1. Prepare your keypair file
2. Run the example:

```bash theme={null}
bun run index.ts path/to/keypair.json [optional-swig-address]
```

The example will:

* Create or use an existing Swig wallet
* Set up necessary token accounts
* Get the best swap route from Jupiter
* Execute the swap with proper instruction handling

## Production Considerations

1. **Security**:
   * Securely manage keypairs and private keys
   * Implement proper error recovery mechanisms
   * Add transaction timeout handling

2. **Performance**:
   * Adjust compute budget based on swap complexity
   * Consider using RPC endpoints with higher rate limits
   * Implement proper retry mechanisms

3. **User Experience**:
   * Add progress indicators for multi-step operations
   * Implement proper balance checking and updates
   * Add slippage protection options

For more information, check out:

* [Jupiter API Documentation](https://station.jup.ag/docs/apis/overview)
* [Swig Documentation](https://docs.swig.rs/)
