Integration: Cross Program Invocation (CPI)

To integrate your program with Jupiter Swap, you can choose between two approaches:

🚧

CPI Limitations

As of August 2023, using the CPI approach comes with trade-offs. Due to Solana's transaction size limit of 1,232 bytes, swaps via CPI are likely to fail at runtime, as Jupiter routes may involve multiple DEXes to minimize price impact. You could set a limit on the number of accounts used for swaps via Jupiter's Swap API to fit within your requirements. However, limiting the accounts will likely result in greater price impact.

Note: When using Jupiter's API, you can set maxAccounts to reduce the number of accounts.

Use Flash-Fill

Instead, we recommend the Flash-Fill approach. Flash-Fill takes advantage of Versioned Transactions combined with Address Lookup Tables, allowing more accounts per transaction while staying within the 1,232-byte limit.

Example

This is an example transaction that utilizes Jupiter Swap via CPI to swap from any token to SOL. This works even if the user doesn't have enough SOL. You can also allow a third-party payer to cover the transaction fees if the user has no SOL at all.

How Does This Work?

For CPI to function, the transaction consists of the following instructions:

  1. Borrow enough SOL from the program to open a wSOL account owned by the program.
  2. Swap the user's X token for wSOL on Jupiter via CPI.
  3. Close the wSOL account and send it back to the program.
  4. The program then transfers the SOL back to the user.

Code Repo

You can find the GitHub repository here: https://github.com/jup-ag/sol-swap-cpi. Be sure to check out both the program code and the client code.

You can also refer to the transaction on-chain to see how it works.

Rust Crate

To simplify integration via CPI, you can add the following crate to your program: jupiter-cpi. This will help streamline the process of incorporating Jupiter Swap via Cross Program Invocation.

Cargo.toml

[dependencies]
jupiter-cpi = { git = "https://github.com/jup-ag/jupiter-cpi", rev = "5eb8977" }
... other dependencies
use jupiter_cpi;

...

let signer_seeds: &[&[&[u8]]] = &[...];

// pass accounts to context one-by-one and construct accounts here.
// Or in practise, it may be easier to use `remaining_accounts` https://book.anchor-lang.com/anchor_in_depth/the_program_module.html
let accounts = jupiter_cpi::cpi::accounts::SharedAccountsRoute {
    token_program: ,
    program_authority: ,
    user_transfer_authority: ,
    source_token_account: ,
    program_source_token_account: ,
    program_destination_token_account: ,
    destination_token_account: ,
    source_mint: ,
    destination_mint: ,
    platform_fee_account: ,
    token_2022_program: ,
};

let cpi_ctx = CpiContext::new_with_signer(
    ctx.accounts.jup.to_account_info(),
    accounts,
    signer_seeds,
);

jupiter_cpi::cpi::shared_accounts_route(
    cpi_ctx,
    id,
    route_plan,
    in_amount,
    quoted_out_amount,
    slippage_bps,
    platform_fee_bps,
)?;

...