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

# Swap Instruction

> Core swap instruction for executing trades between RWAs and stablecoins

## Overview

The `swap` instruction is the core trading operation of the Multiliquid Program, enabling atomic swaps between Real World Asset (RWA) tokens and stablecoins. It supports both swap directions and both exact-in and exact-out modes.

### Key Responsibilities

* Execute bidirectional swaps between RWAs and stablecoins
* Calculate swap amounts using NAV-based pricing
* Apply protocol fees and LP fees
* Validate all pause states before execution
* Emit comprehensive swap events

## Swap Instruction

### Function Signature

```rust theme={null}
pub fn swap(
    ctx: Context<Swap>,
    amount: u64,
    min_amount_out: Option<u64>,
    max_amount_in: Option<u64>,
    swap_direction: SwapDirection,
    swap_type: SwapType,
) -> Result<()>
```

### Parameters

| Parameter        | Type            | Description                                             |
| ---------------- | --------------- | ------------------------------------------------------- |
| `amount`         | `u64`           | Primary amount (input for ExactIn, output for ExactOut) |
| `min_amount_out` | `Option<u64>`   | Minimum output (slippage protection for ExactIn)        |
| `max_amount_in`  | `Option<u64>`   | Maximum input (slippage protection for ExactOut)        |
| `swap_direction` | `SwapDirection` | Direction of the swap                                   |
| `swap_type`      | `SwapType`      | ExactIn or ExactOut mode                                |

### Swap Direction

```rust theme={null}
pub enum SwapDirection {
    StableToAsset,  // Stablecoin → RWA
    AssetToStable,  // RWA → Stablecoin
}
```

### Swap Type

```rust theme={null}
pub enum SwapType {
    ExactIn,   // User specifies exact input amount
    ExactOut,  // User specifies exact output amount
}
```

### Required Accounts

```rust theme={null}
#[derive(Accounts)]
pub struct Swap<'info> {
    // Signer
    pub user: Signer<'info>,

    // Pair account (PDA seeded by liquidity_provider, stable mint, asset mint)
    pub pair: Account<'info, Pair>,

    // Program authority PDA (owns the stablecoin fee vault)
    pub program_authority: UncheckedAccount<'info>,

    // Liquidity provider wallet (referenced in PDA seeds)
    pub liquidity_provider: UncheckedAccount<'info>,

    // LP-specific vault authority PDA (signs LP vault transfers)
    pub lp_vault_authority: UncheckedAccount<'info>,

    // Token mints
    pub stable_coin_mint_address: InterfaceAccount<'info, Mint>,
    pub asset_token_mint_address: InterfaceAccount<'info, Mint>,

    // User token accounts
    pub asset_token_user_token_account: InterfaceAccount<'info, TokenAccount>,
    pub stable_coin_user_token_account: InterfaceAccount<'info, TokenAccount>,

    // LP vault token accounts (ATAs owned by lp_vault_authority)
    pub stable_coin_vault_token_account: InterfaceAccount<'info, TokenAccount>,
    pub asset_token_vault_token_account: InterfaceAccount<'info, TokenAccount>,

    // Configuration accounts
    pub global_config: Account<'info, GlobalConfig>,
    pub fee_token_account: InterfaceAccount<'info, TokenAccount>,
    pub rwa_config: Account<'info, AssetConfig>,
    pub stable_config: Account<'info, AssetConfig>,
    pub lp_stable_config: Account<'info, LpStableConfig>,

    // Token programs (one per mint, supporting Token and Token-2022)
    pub token_program_stable: Interface<'info, TokenInterface>,
    pub token_program_asset: Interface<'info, TokenInterface>,

    // NAV accounts passed via remaining_accounts
    // ... up to 5 NAV source accounts per asset
}
```

### Validation Checks

Before executing the swap, the instruction validates:

1. **Pause States**: Program, both assets, pair, and LP config must be unpaused
2. **Asset Types**: RWA must be `AssetType::Rwa`, stablecoin must be `AssetType::Stable`
3. **Amount**: Must be greater than zero
4. **NAV Prices**: Both assets must return valid, non-zero NAV prices
5. **Slippage**: Calculated output/input must satisfy min/max constraints
6. **Combined StableToAsset Fees**: `protocol_fees_bps + redemption_fee_bps` must not exceed 10000

### Events

```rust theme={null}
#[event]
pub struct SwapExecuted {
    pub requestor: Pubkey,          // User wallet
    pub amount_in: u64,             // Actual input amount
    pub protocol_fee_amount: u64,   // Protocol fees collected
    pub discount_bps: u16,          // LP fee applied (redemption or discount)
    pub amount_out: u64,            // Actual output amount
    pub pair: Pubkey,               // Pair account address
    pub swap_direction: SwapDirection,
    pub swap_type: SwapType,
}
```

## Swap Calculation

### NAV-Based Pricing

<Note>
  **Deterministic Pricing**: The Multiliquid Program uses NAV-based pricing, not AMM-style liquidity curves. Prices are determined by asset NAV values, not by liquidity depth. There is no price impact from trade size.
</Note>

The swap amount is calculated using the exchange rate between asset NAVs:

```
output_amount = input_amount × input_nav / output_nav
```

### Fee Application

Fees are applied in a specific order depending on swap direction:

#### StableToAsset (Stablecoin → RWA)

1. **Combined Fees**: Protocol fees and redemption fee are calculated simultaneously from the input amount
2. **Exchange Rate**: Apply NAV ratio to the post-fee amount to calculate RWA output

```
total_fees_bps = protocol_fees_bps + redemption_fee_bps
protocol_fees = ceil(amount × protocol_fees_bps / 10000)
total_fees = ceil(amount × total_fees_bps / 10000)
amount_after_fees = amount - total_fees
rwa_output = amount_after_fees × stable_nav / rwa_nav
```

#### AssetToStable (RWA → Stablecoin)

1. **Exchange Rate**: Apply NAV ratio to calculate stablecoin equivalent
2. **Discount Rate**: Apply LP discount fee
3. **Protocol Fees**: Deducted from discounted amount

```
stable_equivalent = rwa_amount × rwa_nav / stable_nav
after_discount = stable_equivalent - (stable_equivalent × discount_rate_bps / 10000)
stable_output = after_discount - protocol_fee
```

### Decimal Normalization

All calculations use 128-bit arithmetic with proper decimal handling:

* NAV prices normalized to 9 decimals
* Intermediate calculations use combined decimal precision
* Final amounts rounded appropriately (ceil for fees, floor for outputs)

## Usage Examples

### ExactIn: Stable → RWA

Swap exactly 1000 USDC for RWA tokens with minimum output protection:

```typescript theme={null}
import { BN } from "@coral-xyz/anchor";

const amount = new BN(1000_000000);  // 1000 USDC (6 decimals)
const minAmountOut = new BN(990_000000);  // Minimum 990 RWA tokens

await program.methods
  .swap(
    amount,
    minAmountOut,    // min_amount_out
    null,            // max_amount_in (not used for ExactIn)
    { stableToAsset: {} },
    { exactIn: {} }
  )
  .accounts({
    user: wallet.publicKey,
    pair,
    programAuthority,
    liquidityProvider,
    lpVaultAuthority,
    stableCoinMintAddress,
    assetTokenMintAddress,
    assetTokenUserTokenAccount,
    stableCoinUserTokenAccount,
    stableCoinVaultTokenAccount,
    assetTokenVaultTokenAccount,
    globalConfig,
    feeTokenAccount,
    rwaConfig,
    stableConfig,
    lpStableConfig,
    tokenProgramStable: TOKEN_PROGRAM_ID,
    tokenProgramAsset: TOKEN_PROGRAM_ID,
  })
  .remainingAccounts(navAccounts)  // NAV source accounts
  .rpc();
```

### ExactOut: Stable → RWA

Receive exactly 1000 RWA tokens, spending at most a specified USDC amount:

```typescript theme={null}
const amount = new BN(1000_000000);  // Exact 1000 RWA tokens out
const maxAmountIn = new BN(1010_000000);  // Maximum 1010 USDC in

await program.methods
  .swap(
    amount,
    null,            // min_amount_out (not used for ExactOut)
    maxAmountIn,     // max_amount_in
    { stableToAsset: {} },
    { exactOut: {} }
  )
  .accounts({
    // ... same accounts as above
  })
  .remainingAccounts(navAccounts)
  .rpc();
```

### ExactIn: RWA → Stable

Swap exactly 1000 RWA tokens for stablecoins:

```typescript theme={null}
const amount = new BN(1000_000000);  // 1000 RWA tokens
const minAmountOut = new BN(995_000000);  // Minimum 995 USDC

await program.methods
  .swap(
    amount,
    minAmountOut,
    null,
    { assetToStable: {} },
    { exactIn: {} }
  )
  .accounts({
    // ... accounts
  })
  .remainingAccounts(navAccounts)
  .rpc();
```

### ExactOut: RWA → Stable

Receive exactly 1000 USDC, spending at most a specified RWA amount:

```typescript theme={null}
const amount = new BN(1000_000000);  // Exact 1000 USDC out
const maxAmountIn = new BN(1005_000000);  // Maximum 1005 RWA in

await program.methods
  .swap(
    amount,
    null,
    maxAmountIn,
    { assetToStable: {} },
    { exactOut: {} }
  )
  .accounts({
    // ... accounts
  })
  .remainingAccounts(navAccounts)
  .rpc();
```

## Error Codes

| Error                        | Description                                                   |
| ---------------------------- | ------------------------------------------------------------- |
| `ProgramPaused`              | Program is paused                                             |
| `RwaPaused`                  | RWA asset is paused                                           |
| `StablePaused`               | Stablecoin or LP stable config is paused                      |
| `PairPaused`                 | Trading pair is paused                                        |
| `AmountMustBePositive`       | Amount is zero                                                |
| `InvalidAssetType`           | Asset types don't match expected (RWA vs Stable)              |
| `AmountOutTooLow`            | Output less than minimum                                      |
| `AmountInTooHigh`            | Input more than maximum                                       |
| `FeesOutOfRange`             | StableToAsset protocol plus redemption fees exceed 10000 BPS  |
| `ProtocolFeesMustBePositive` | Nonzero configured protocol fee rounded to zero for the trade |
| `DiscountMustBePositive`     | Nonzero configured LP fee rounded to zero for the trade       |
| `AmountInMustBePositive`     | Calculated vault input is zero                                |
| `AmountOutMustBePositive`    | Calculated output is zero                                     |
| `InvalidNav`                 | NAV sources returned invalid or divergent data                |
| `MathOverflow`               | Calculation overflow                                          |

## Access Control

**Access**: Permissionless

Any wallet can execute swaps provided:

* All pause states are inactive
* User has sufficient token balance
* User has approved token transfers
* Valid NAV prices are available

***

<Card title="Next: Global Configuration" icon="file-code" href="/svm/instructions/global-config">
  Learn about program-wide configuration management
</Card>
