Self-contained Rust builders for Prism find_arb_v2 and find_arb_v3 instructions.
Prism is an on-chain Solana arbitrage execution program with a just-in-time routing engine. Callers submit a pool menu plus the required market accounts in a fully specified instruction; at execution time, Prism reads those supplied pools on-chain, finds an executable route across them, automatically chooses the swap input amount to maximize value for the submitted arb opportunity, and executes it through the supported DEX programs. The live program is Prism8hsRo6Ww5jiN5Zeh3YDPLZHqHduCPSAV7JF7qv. Use find_arb_v2 for direct walk-depth control. V3 accepts the same pool menus and adds budget-based sizing when the winning candidate is Pump/DLMM.
This crate is intentionally narrow. Callers must provide every account pubkey from their own indexer, parser, cache, or configuration. The SDK does not fetch accounts, discover pools, create ATAs, infer markets, send transactions, choose lookup tables, manage compute budget, or validate account-lock limits.
- Supported Programs
- Route Shape
- Rust Examples
- Instruction Data
- Settlement Accounts
- Account Prefix
- Market IDs
- Market Accounts
- Emitted Pool Slices
- Common On-chain Errors
- Build Errors
find_arb_v2 and find_arb_v3 support up to 3-hop arbitrage. They do not build or execute routes with more than three swap legs.
The base mint and route_mints fields have the same meaning for both shapes. base is the cycle's base token, and route_mints contains every non-base mint the submitted pool graph may touch. For a 2-hop route, that is usually one target mint. For a 3-hop route, include both non-base mints in the triangle.
pools is an unordered pool menu, not an ordered route. Prism reads each pool's endpoint mints on-chain, builds the candidate graph, and chooses the executable route order itself. Pools that touch base can become direct edges for 2-hop routes. Pools that do not touch base, but connect two submitted route_mints, can become the middle bridge edge of a 3-hop route. Submitting bridge pools for possible 3-hop routes does not disable 2-hop evaluation; Prism evaluates direct 2-hop candidates from the same pool menu when matching base-touching pools are present. The order of pools only controls instruction serialization; it does not force route execution order.
The SDK does no account discovery. With the required pubkeys in scope, put them into the typed parameters:
In V2, max_dynamic_walk_steps controls dynamic liquidity walks on the selected route. It caps Meteora DLMM bin scans and Raydium CLMM, Orca Whirlpool, PancakeSwap, and Byreal tick-walk steps per direction; constant-product pools do not use it. Higher values can reach deeper liquidity but use more compute, while lower values save compute but can miss deeper routes.
use prism_client_sdk::{
build_find_arb_v2_instruction, FindArbV2Params, MintAccount,
markets::{
meteora::MeteoraDlmmAccounts,
raydium::{RaydiumCpAccounts, RaydiumV4Accounts},
MarketAccounts,
},
};
use solana_pubkey::Pubkey;
const WSOL_MINT: Pubkey = Pubkey::from_str_const("So11111111111111111111111111111111111111112");
const USDC_MINT: Pubkey = Pubkey::from_str_const("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");
const TRUMP_MINT: Pubkey = Pubkey::from_str_const("6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN");
const SPL_TOKEN: Pubkey = Pubkey::from_str_const("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA");
let ix = build_find_arb_v2_instruction(FindArbV2Params {
signer,
base: MintAccount {
mint: WSOL_MINT,
token_program: SPL_TOKEN,
user_ata: wsol_user_ata,
},
flashloan: true,
fail_if_no_profit: true,
min_profit_base_units: 10_000,
max_dynamic_walk_steps: 12,
route_mints: vec![MintAccount {
mint: USDC_MINT,
token_program: SPL_TOKEN,
user_ata: usdc_user_ata,
}],
pools: vec![
MarketAccounts::RaydiumV4(RaydiumV4Accounts {
pool_state: Pubkey::from_str_const("58oQChx4yWmvKdwLLZzBi4ChoCc2fqCUWBkwMihLYQo2"),
coin_vault: Pubkey::from_str_const("DQyrAcCrDXQ7NeoqGgDCZwBvWDcYmFCjSb9JtteuvPpz"),
pc_vault: Pubkey::from_str_const("HLmqeL62xR1QoZ1HKKbXRrdN1p3phKpxRMb2VVopvBBz"),
}),
MarketAccounts::RaydiumCp(RaydiumCpAccounts {
pool_state: Pubkey::from_str_const("47hq28mcL7q5GhBg7epyGF2dnuJd4MKFt8QhT7CzYUp4"),
amm_config: Pubkey::from_str_const("BgxH5ifebqHDuiADWKhLjXGP5hWZeZLoCdmeWJLkRqLP"),
token_0_vault: Pubkey::from_str_const("9tAoQUNB1wKnBSUyc6ukg2pWbeofZJVHxur2UaRBZNZc"),
token_1_vault: Pubkey::from_str_const("BArWLNarRzS7N1GCwBjNgVnC4866c8oJNRqhb5axf6y4"),
token_0_mint: WSOL_MINT,
token_1_mint: USDC_MINT,
observation_state: Pubkey::from_str_const("AwXcFysn5vntDyiGo9hXDhTMFSg2in7hxj8ED51oZgqo"),
}),
],
})?;This builds a two-pool menu for a 2-hop candidate. The SDK assembles the instruction; the caller chooses pools whose endpoint mints match base and route_mints.
V3 accepts every pool menu supported by V2. When the winning candidate is Pump/DLMM, Prism uses the explicit CU budget to size its DLMM walk. Other winners use max_dynamic_walk_steps.
use prism_client_sdk::{
build_find_arb_v3_instruction, FindArbV3Params,
markets::{
meteora::MeteoraDlmmAccounts,
pumpfun::PumpfunAmmAccounts,
raydium::RaydiumCpAccounts,
MarketAccounts,
},
};
let ix = build_find_arb_v3_instruction(FindArbV3Params {
signer,
base,
flashloan: true,
fail_if_no_profit: true,
min_profit_base_units: 10_000,
max_dynamic_walk_steps: 12,
prism_cu_budget: 320_000,
route_mints,
pools: vec![
MarketAccounts::PumpfunAmm(PumpfunAmmAccounts { /* ... */ }),
MarketAccounts::RaydiumCp(RaydiumCpAccounts { /* ... */ }),
MarketAccounts::MeteoraDlmm(MeteoraDlmmAccounts { /* ... */ }),
],
})?;V2 and V3 accept the same account prefix and unordered pool menu. Both support 2-hop and 3-hop routes.
For either builder, a 3-hop candidate supplies both non-base mints and three markets that form BASE ↔ A ↔ B ↔ BASE:
let route_mints = vec![
MintAccount {
mint: USDC_MINT,
token_program: SPL_TOKEN,
user_ata: usdc_user_ata,
},
MintAccount {
mint: TRUMP_MINT,
token_program: SPL_TOKEN,
user_ata: trump_user_ata,
},
];
let pools = vec![
// WSOL ↔ USDC
MarketAccounts::RaydiumV4(RaydiumV4Accounts { /* ... */ }),
// USDC ↔ TRUMP (the bridge market)
MarketAccounts::MeteoraDlmm(MeteoraDlmmAccounts { /* ... */ }),
// TRUMP ↔ WSOL
MarketAccounts::MeteoraDlmm(MeteoraDlmmAccounts { /* ... */ }),
];The pool entries remain unordered; their mint connectivity determines the executable route.
V2 uses max_dynamic_walk_steps as the caller's walk-depth request.
[7, flags, max_dynamic_walk_steps, num_mints, num_pools, min_profit_base_units_le_u64, market_ids...]
V3 supports the same pools and account metas as V2, and adds a nonzero Prism CU budget. The budget sizes the DLMM walk only when the winning candidate is Pump/DLMM; other winners use max_dynamic_walk_steps.
[11, flags, max_dynamic_walk_steps, num_mints, num_pools, min_profit_base_units_le_u64, prism_cu_budget_le_u32, market_ids...]
prism_cu_budget is for the Prism instruction alone, not the transaction CU limit:
prism_cu_budget =
requested_transaction_cu_limit
- conservative_reserve_for_all_non_prism_instructions
- caller_transaction_margin
The caller chooses the reserve and margin. The SDK only validates that the budget is nonzero and serializes it.
min_profit_base_units is denominated in the submitted base mint's atomic
units. For WSOL this is native lamports. For USDC, USDT, and USD1 it is
6-decimal token units; callers that use a native SOL lander tip must convert
that tip value into base units before building the instruction.
Flags:
bit 0: flashloan
bit 1: fail_if_no_profit
num_mints must be non-zero. The route mint list must not contain the base mint and must not contain duplicate mint pubkeys. The SDK does not expose Prism's high internal safety caps as client-side routing limits.
Prism has one vault authority:
VAULT_AUTH = PDA([b"vault_auth", WSOL_MINT], PRISM_PROGRAM_ID)
= 6jM8tJbomfcjgP343TsT13duo7bxvEVq5jftjPytDq6M
Prism supports four SPL Token base mints for settlement: WSOL, USDC, USDT, and USD1. Any other base mint is rejected before route execution.
Flashloan mode is available only for WSOL and USDC base mints. The vault account is the SPL-token ATA owned by VAULT_AUTH for the selected base mint:
WSOL vault = ATA(VAULT_AUTH, WSOL_MINT, SPL_TOKEN)
= AsnFKUNo4oXzHuu91WTgB2mUT1bcsx9kKyurhAyeur56
USDC vault = ATA(VAULT_AUTH, USDC_MINT, SPL_TOKEN)
= ApvRzpyA7EXKqGaZ78JPXyjyFUFTqRaSDenPj95dPows
When flashloan = true, the SDK emits the selected vault ATA plus VAULT_AUTH in the account prefix. Prism borrows the current vault balance into the signer's base ATA, executes the selected route, then transfers principal plus protocol fee from the signer's base ATA back into the same vault. That means successful flashloan fees accrue directly in the WSOL or USDC flashloan vault.
When flashloan = false, there is no vault authority account in the prefix. FEE_OWNER is the same pubkey as VAULT_AUTH, and the SDK emits only the writable fee recipient ATA:
WSOL fee ATA = ATA(FEE_OWNER, WSOL_MINT, SPL_TOKEN)
= AsnFKUNo4oXzHuu91WTgB2mUT1bcsx9kKyurhAyeur56
USDC fee ATA = ATA(FEE_OWNER, USDC_MINT, SPL_TOKEN)
= ApvRzpyA7EXKqGaZ78JPXyjyFUFTqRaSDenPj95dPows
USDT fee ATA = ATA(FEE_OWNER, USDT_MINT, SPL_TOKEN)
= 9a76tENsmkTumYbA46r6FD9raFb74RKNcJ4ey4R61gwt
USD1 fee ATA = ATA(FEE_OWNER, USD1_MINT, SPL_TOKEN)
= Egv1XeHAL4LxU59jDgQm3Q7jeqAm5SSyq8xGjEdHDZzh
This non-flashloan path supports WSOL, USDC, USDT, and USD1. The transfer is fee-only; no principal is repaid because Prism did not borrow from a vault.
Prism charges a 10% protocol fee only on realized profit from profitable arbitrage. The fee is paid through the selected flashloan vault or non-flashloan fee-recipient ATA. Failed attempts and attempts where Prism finds no profitable route do not pay this protocol fee.
The SDK computes these addresses internally. It also exposes prism_flashloan_vault_accounts(base_mint), prism_fee_recipient_ata(base_mint, base_token_program), prism_base_mint_supported(base_mint), and associated_token_address(owner, mint, token_program) for callers that want to inspect or pre-create the same accounts.
Base prefix:
0 signer writable signer
1 base user ATA writable
2 base mint readonly
3 base token program readonly
Flashloan prefix appends:
4 Prism base vault ATA writable
5 Prism base vault auth readonly
Non-flashloan prefix appends:
4 Prism fee ATA writable
The flashloan prefix supports WSOL and USDC. The non-flashloan prefix supports WSOL, USDC, USDT, and USD1.
Each route mint appends:
token program readonly
user ATA writable
0 RaydiumV4
1 RaydiumCp
2 RaydiumClmm
3 OrcaWhirlpool
5 MeteoraDammV2
6 MeteoraPools
7 PumpfunAmm
8 Pancakeswap
9 MeteoraDlmm
10 RaydiumClmmT22
11 PancakeswapT22
12 OrcaWhirlpoolT22
13 ByrealClmm
14 ByrealClmmT22
15 HumidifiSwapV2
16 HumidifiSwap
17 Manifest
18 AlphaQ
19 AlphaQT22
20 GoonfiV2
21 SolfiV2
22 FutarchySpot
23 Fusion
24 BisonFi
25 Tessera
26 ZeroFi
28 GoonfiV2T22
29 ByrealDynamic
These are wire IDs emitted by this SDK. Legacy DLMM wire ID 4 is intentionally not exposed: MeteoraDlmm always emits wire ID 9 and the 16-account swap2 layout, including for SPL/SPL pools. The deprecated MarketAccounts::MeteoraDlmmT22 and MarketId::MeteoraDlmmT22 names remain source aliases for the same wire ID 9 and layout; they do not emit ID 4.
Callers pass FindArbV2Params or FindArbV3Params with pools: Vec<MarketAccounts>, where MarketAccounts lives under prism_client_sdk::markets. Each variant wraps a market-specific struct from its family module, such as markets::raydium::RaydiumV4Accounts or markets::meteora::MeteoraDlmmAccounts, with only the dynamic pubkeys the caller must know. The SDK derives the wire market ID, inserts Prism's fixed program IDs, authorities, sysvars, event authorities, and token-program constants, then emits the full remaining-account list in Prism's order with the correct writable/readonly flags.
There is no separate market id field to keep in sync with a raw pubkey slice. If the variant is MarketAccounts::RaydiumV4, the instruction data receives market id 0 and the Raydium v4 account layout is emitted.
The following paired families use one caller-facing variant for SPL Token and Token-2022 pools:
MarketAccounts::RaydiumClmm
MarketAccounts::OrcaWhirlpool
MarketAccounts::MeteoraDlmm
MarketAccounts::Pancakeswap
MarketAccounts::ByrealClmm
MarketAccounts::AlphaQ
MarketAccounts::GoonfiV2
Supply both endpoint mint addresses and their exact token program IDs in the account struct. DLMM validates both IDs but always emits its swap2 wire ID and slice. For the other paired families, both SPL Token programs select the normal wire ID and either Token-2022 program selects the T22 wire ID and slice. AlphaQ is narrower: it supports SPL/SPL and Token-2022-left/SPL-right only. Unsupported program IDs and unsupported AlphaQ orientations return BuildError.
This selection is deterministic and performs no RPC calls. The caller remains responsible for reading the mint owners or otherwise supplying the correct token program IDs. MarketAccounts::try_market_id() and try_account_count() expose the same checked resolution used by both arb builders; invalid token programs never produce a public wire ID or count.
The remaining explicit MarketAccounts::*T22 variants are temporarily available as deprecated compatibility aliases. The deprecated MeteoraDlmmT22 alias accepts either SPL or Token-2022 programs and resolves to the canonical ID 9 Swap2 layout. Other checked aliases reject an all-SPL selection, and AlphaQT22 specifically requires Token-2022-left/SPL-right. The legacy RaydiumClmmT22Accounts, PancakeswapT22Accounts, and ByrealClmmT22Accounts structs do not carry token-program fields, so those three aliases retain forced-T22 behavior that the SDK cannot validate from their inputs.
Documented optional placeholders are represented as Option<Pubkey>:
MeteoraDlmmAccounts.host_fee_in
None emits the DLMM program id placeholder.
MeteoraDammV2Accounts.instructions_sysvar_or_program_sentinel
Some(SYSVAR_INSTRUCTIONS) for rate-limiter pools.
None emits the DAMM v2 program id sentinel.
PumpfunAmmAccounts.user_volume_accumulator_wsol_ata
Some(account) for cashback pools.
None emits the Pumpfun AMM program id placeholder.
PumpfunAmmAccounts.pool_v2
Some(account) for creator-feature pools.
None emits the Pumpfun AMM program id placeholder.
CLMM current tick-array placeholder:
RaydiumClmm, Pancakeswap, and ByrealClmm also accept the family's DEX program id in tick_array_cur. Use this only after checking that the mathematical current tick-array PDA does not exist, or when another supplied tick-array slot intentionally carries the first valid tick array for the swap direction. tick_array_prev and tick_array_next must not be program-id placeholders; any slot Prism may use as the first CPI tick array must be a loadable tick-array account.
All other fields are required. The SDK does not invent dynamic pool accounts, derive user ATAs, discover token programs, choose tick arrays, check tick-array existence, or fetch state. It only selects a wire layout from the token programs the caller supplied.
The SDK emits each pool as one contiguous account slice. The slice order must match the MarketAccounts variant order in FindArbV2Params.pools or FindArbV3Params.pools, because Prism slices the remaining accounts by the emitted market_ids.
Legend:
W writable
read-only
SDK constant inserted by the SDK
caller supplied through the typed account struct
0 W pool_state caller
1 Raydium v4 authority SDK constant
2 W coin_vault caller
3 W pc_vault caller
4 Raydium v4 program SDK constant
0 W pool_state caller
1 amm_config caller
2 Raydium CP vault authority SDK constant
3 W token_0_vault caller
4 W token_1_vault caller
5 token_0_mint caller
6 token_1_mint caller
7 W observation_state caller
8 Raydium CP program SDK constant
Used by RaydiumClmm, Pancakeswap, and ByrealClmm.
0 amm_config caller
1 W pool_state caller
2 W token_vault_0 caller
3 W token_vault_1 caller
4 W observation_state caller
5 SPL Token program SDK constant
6 DEX program SDK constant for variant
7 W tick_array_bitmap_ext caller
8 W tick_array_prev caller
9 W tick_array_cur caller, or DEX program id placeholder
10 W tick_array_next caller
Automatically selected for RaydiumClmm, Pancakeswap, and ByrealClmm when either supplied endpoint token program is Token-2022.
0 amm_config caller
1 W pool_state caller
2 W token_vault_0 caller
3 W token_vault_1 caller
4 W observation_state caller
5 SPL Token program SDK constant
6 Token-2022 program SDK constant
7 Memo v3 program SDK constant
8 token_mint_0 caller
9 token_mint_1 caller
10 DEX program SDK constant for variant
11 W tick_array_bitmap_ext caller
12 W tick_array_prev caller
13 W tick_array_cur caller, or DEX program id placeholder
14 W tick_array_next caller
0 SPL Token program SDK constant
1 W whirlpool caller
2 W vault_a caller
3 W vault_b caller
4 W tick_array_prev caller
5 W tick_array_cur caller
6 W tick_array_next caller
7 W oracle caller
8 Orca Whirlpool program SDK constant
Automatically selected for OrcaWhirlpool when either supplied endpoint token program is Token-2022.
0 token_program_a caller
1 token_program_b caller
2 Memo v3 program SDK constant
3 W whirlpool caller
4 token_mint_a caller
5 token_mint_b caller
6 W vault_a caller
7 W vault_b caller
8 W tick_array_prev caller
9 W tick_array_cur caller
10 W tick_array_next caller
11 W oracle caller
12 Orca Whirlpool program SDK constant
MeteoraDlmm always emits this layout for both SPL Token and Token-2022 pools. The SDK does not expose or emit legacy wire ID 4. Its deprecated MeteoraDlmmT22 source alias emits this same layout and wire ID 9.
0 W lb_pair caller
1 W bin_array_bitmap_ext caller
2 W reserve_x caller
3 W reserve_y caller
4 token_x_mint caller
5 token_y_mint caller
6 W oracle caller
7 W host_fee_in or DLMM placeholder caller option or SDK constant
8 token_x_program caller
9 token_y_program caller
10 Memo v3 program SDK constant
11 DLMM event authority SDK constant
12 DLMM program SDK constant
13 W bin_array_prev caller
14 W bin_array_cur caller
15 W bin_array_next caller
The prev/cur/next field names are retained API names for the three fixed
slots. Bitmap-aware callers may supply a compact directional live-array union
there, including duplicated or gap-shifted arrays; Prism validates and orders
the accounts for Swap2 on-chain.
0 pool authority SDK constant
1 W pool caller
2 W token_a_vault caller
3 W token_b_vault caller
4 token_a_mint caller
5 token_b_mint caller
6 token_a_program caller
7 token_b_program caller
8 DAMM v2 event authority SDK constant
9 DAMM v2 program SDK constant
10 instructions sysvar or sentinel caller option or SDK constant
0 W pool caller
1 W a_vault caller
2 W b_vault caller
3 W a_token_vault caller
4 W b_token_vault caller
5 W a_vault_lp_mint caller
6 W b_vault_lp_mint caller
7 W a_vault_lp caller
8 W b_vault_lp caller
9 W protocol_fee_a caller
10 W protocol_fee_b caller
11 vault_program caller
12 SPL Token program SDK constant
13 Meteora Pools program SDK constant
0 W pool caller
1 global config SDK constant
2 base_mint caller
3 quote_mint caller
4 W pool_base_vault caller
5 W pool_quote_vault caller
6 fee_recipient caller
7 W fee_recipient_ata caller
8 base_token_program caller
9 quote_token_program caller
10 system program SDK constant
11 associated token program SDK constant
12 event authority SDK constant
13 Pumpfun AMM program SDK constant
14 W creator_vault_ata caller
15 creator_vault_authority caller
16 global accumulator SDK constant
17 W user_volume_accumulator caller
18 fee_config SDK constant
19 fee_program SDK constant
20 W user_volume_accumulator_wsol_ata caller option when present
20 Pumpfun AMM placeholder SDK constant when option is None
21 pool_v2 or Pumpfun placeholder caller option or SDK constant
22 swap_fee_recipient caller
23 W swap_fee_ata caller
0 W pool caller
1 W base_vault caller
2 W quote_vault caller
3 clock sysvar SDK constant
4 instructions sysvar SDK constant
5 base_mint caller
6 quote_mint caller
7 W side_table caller
8 jito_vote caller
9 HumidiFi program SDK constant
0 W pool caller
1 W base_vault caller
2 W quote_vault caller
3 clock sysvar SDK constant
4 instructions sysvar SDK constant
5 jito_vote caller
6 HumidiFi program SDK constant
0 W market caller
1 W base_vault caller
2 W quote_vault caller
3 base_mint caller
4 quote_mint caller
5 system program SDK constant
6 Manifest program SDK constant
0 W pool caller
1 W market_stats caller
2 W vault_left caller
3 W vault_right caller
4 instructions sysvar SDK constant
5 SPL Token program SDK constant
6 mint_left caller
7 mint_right caller
8 AlphaQ program SDK constant
Automatically selected for AlphaQ when token_program_left is Token-2022 and token_program_right is SPL Token.
0 W pool caller
1 W market_stats caller
2 W vault_left caller
3 W vault_right caller
4 instructions sysvar SDK constant
5 SPL Token program SDK constant
6 mint_left caller
7 mint_right caller
8 AlphaQ program SDK constant
9 Token-2022 program SDK constant
0 W pair caller
1 W vault_a caller
2 W vault_b caller
3 mint_a caller
4 mint_b caller
5 side_price caller
6 W global_state caller
7 instructions sysvar SDK constant
8 SPL Token program SDK constant
9 GoonFi v2 program SDK constant
Automatically selected for GoonfiV2 when either supplied endpoint token program is Token-2022.
0 W pair caller
1 W vault_a caller
2 W vault_b caller
3 mint_a caller
4 mint_b caller
5 side_price caller
6 W global_state caller
7 instructions sysvar SDK constant
8 SPL Token program SDK constant
9 Token-2022 program SDK constant
10 GoonFi v2 program SDK constant
0 W pool caller
1 oracle caller
2 W side_a caller
3 W vault_a caller
4 W side_b caller
5 W vault_b caller
6 mint_a caller
7 mint_b caller
8 instructions sysvar SDK constant
9 ZeroFi program SDK constant
0 W pair caller
1 oracle caller
2 global_config caller
3 W base_vault caller
4 W quote_vault caller
5 instructions sysvar SDK constant
6 base_mint caller
7 quote_mint caller
8 base_token_program caller
9 quote_token_program caller
10 SolFi v2 program SDK constant
0 W dao caller
1 W amm_base_vault caller
2 W amm_quote_vault caller
3 event authority SDK constant
4 Futarchy program SDK constant
0 token_program_a caller
1 token_program_b caller
2 Memo v3 program SDK constant
3 W pool caller
4 token_mint_a caller
5 token_mint_b caller
6 W token_vault_a caller
7 W token_vault_b caller
8 W tick_array_cur caller
9 W tick_array_above_1 caller
10 W tick_array_above_2 caller
11 W tick_array_below_1 caller
12 W tick_array_below_2 caller
13 Fusion program SDK constant
0 W pool caller
1 W vault_a caller
2 W vault_b caller
3 instructions sysvar SDK constant
4 trailing account SDK constant
5 BisonFi program SDK constant
6 Prism program SDK constant
To comply with BisonFi's account enforcement, the SDK automatically includes
the Jito vote account J1to1yufRnoWn81KYg1XkTWzmKjnYSnmE2VY8DGUJ9Qv.
Because Jito bundles reject transactions containing vote accounts, routes that
include BisonFi cannot be submitted through Jito bundles.
Only the pool's canonical mint A -> mint B direction is supported. Supply
BisonFiAccounts only when the desired route consumes mint A and produces mint B;
Prism does not scout or execute the reverse mint B -> mint A edge.
0 global_authority caller
1 W pool caller
2 W mint_a_vault caller
3 W mint_b_vault caller
4 mint_a caller
5 mint_b caller
6 instructions sysvar SDK constant
7 Tessera program SDK constant
Tessera uses the public opcode 0x10 path. The instructions sysvar is quote-critical because
Tessera scans top-level instruction program ids to determine whether its pool fee is waived. The
alternate router-profile opcode 0x11 is intentionally not part of Prism's adapter contract.
The caller is responsible for using the correct dynamic pool, vault, mint, token program, tick/bin array, side-table, fee, and optional sentinel accounts for the selected market.
These are Prism Custom(u32) errors callers commonly see after simulating or sending a find_arb_v2 or find_arb_v3 instruction. Solana logs the same value in hexadecimal as custom program error: 0x....
Account and pool layout errors:
Custom(2000)/0x7d0/NotEnoughAccounts: the account list is shorter than the declared market layouts require.Custom(2012)/0x7dc/UnsupportedBaseMint: the submitted base mint is not WSOL, USDC, USDT, or USD1.Custom(2013)/0x7dd/InvalidRouteTokenAccount: a submittedroute_mints[].user_atais missing, uninitialized, malformed, or owned by a different token program. Refresh it after closing/recreating the account, and supply its matching SPL Token or Token-2022 program.Custom(2014)/0x7de/InvalidSignerBaseTokenAccount: the submitted base token account is missing, uninitialized, malformed, or has a different mint frombase.mint.Custom(2015)/0x7df/InvalidFlashloanVaultAccount: the canonical flashloan vault account is missing, uninitialized, malformed, or has a different mint frombase.mint.Custom(2016)/0x7e0/DuplicateRouteMint: tworoute_mintsentries resolve to the same mint, or one resolves tobase.mint.Custom(3000)/0xbb8/PoolOwnerMismatch: a pool account is not owned by the expected DEX program, usually because the market variant does not match the pool.Custom(3001)/0xbb9/PoolDataSize: a pool account is too short for the expected layout, or the supplied account is stale/wrong for that market.Custom(3003)/0xbbb/PoolMintMismatch: a pool's endpoint mints do not match the submitted base mint and route mint set.Custom(3005)/0xbbd/BinArrayOutOfRange: a Meteora DLMM walk exhausted the supplied bin arrays.Custom(3007)/0xbbf/BinArrayOrderInvalid: Meteora DLMM bin arrays were supplied in the wrong order.Custom(3008)/0xbc0/TickArrayWindowStale: a CLMM tick-array window is stale for the pool's current tick.Custom(3009)/0xbc1/TickArrayDirectionDead: a CLMM pool has no initialized tick arrays on one side, so that direction cannot be executed.
Arb outcome and execution errors:
Custom(5000)/0x1388/NoProfit: Prism found no profitable route. This reverts only whenfail_if_no_profit = true; otherwise the instruction can succeed as a no-op.Custom(5004)/0x138c/Unprofitable: the strict post-swap actual-profit gate failed after execution checks.Custom(5005)/0x138d/SwapCpiFailed: a downstream DEX CPI failed; inspect the transaction logs for the DEX-level cause.Custom(5006)/0x138e/FeeShortfall: the signer's base ATA cannot cover the required settlement transfer after the swaps.
BuildError is a client-side construction error. It means the SDK refused to build an instruction that Prism would reject or that the SDK cannot represent.
| Error | When | Notes |
|---|---|---|
UnsupportedBaseMint(pubkey) |
The V2 or V3 base.mint is not WSOL, USDC, USDT, or USD1, or the base token program is not SPL Token. |
Choose one of Prism's supported settlement base mints. |
UnsupportedFlashloanBaseMint(pubkey) |
flashloan = true and the V2 or V3 base.mint is not WSOL or USDC. |
Disable flashloan for USDT/USD1 routes, or use a WSOL/USDC base mint with an initialized and funded Prism vault. |
RouteMintCountOverflow(count) |
route_mints.len() does not fit the u8 count field in the instruction data. |
This is the wire-format ceiling, not a routing-size recommendation. Real transactions should hit account, byte, or compute budgets first. |
MissingRouteMints |
route_mints is empty. |
Prism needs at least one route mint header to map pool endpoints to user token accounts. Add one MintAccount for each target or bridge mint used by the pool graph. |
BaseMintInRouteMints(pubkey) |
A route mint entry repeats base.mint. |
The base mint is already represented by the V2/V3 params base; remove it from route_mints. |
DuplicateRouteMint(pubkey) |
The same route mint appears more than once. | Deduplicate by mint pubkey and keep the matching token program plus user ATA in the remaining MintAccount. |
MissingPools |
pools is empty. |
Add at least one MarketAccounts variant. The SDK does not infer pools from mints or route intent. |
PoolCountOverflow(count) |
pools.len() does not fit the u8 count field in the instruction data. |
This is the wire-format ceiling, not a routing-size recommendation. Real transactions should hit account, byte, or compute budgets first. |
UnsupportedMarketId(byte) |
markets::MarketId::try_from(byte) received a byte outside the SDK's supported market id range. |
This does not occur when building with typed MarketAccounts variants, because the variant supplies the market id. |
UnsupportedMarketTokenProgram { market, token_program } |
A unified market struct contains a token program other than SPL Token or Token-2022. | Supply the actual owner program of each endpoint mint. |
UnsupportedMarketTokenProgramPair { market, token_program_a, token_program_b } |
The individual programs are recognized, but that market does not support the orientation. | Currently this guards AlphaQ, which supports SPL/SPL and Token-2022-left/SPL-right only. |
InvalidPrismCuBudget |
FindArbV3Params.prism_cu_budget is zero. |
Supply a nonzero Prism-only CU allowance. Use V2 if the caller cannot provide one. |
The SDK does not validate account existence, token account ownership, pool state, pool endpoint mints, route profitability, lookup table fit, compute budget, or transaction account-lock count. Those checks belong to the caller's indexer, simulator, transaction builder, or Prism itself.
Use MarketAccounts::ByrealDynamic(ByrealDynamicAccounts { clmm, token0_pyth_oracle, token1_pyth_oracle }) for pools with decay_fee_flag & 0x10 != 0. clmm is the
existing ByrealClmmAccounts struct, including both endpoint token programs.
This always emits market 29 and 17 accounts, including for SPL/SPL pools.
The first 15 slots are the mint-aware CLMM layout; the final two are read-only
Pyth PriceUpdateV2 accounts in pool token0/token1 order, independent of direction.
Both token programs are checked. Callers resolve oracle accounts matching the
pool's feed IDs and ensure they are updated; the SDK does not fetch pool/oracle
state. Prism validates the oracle identity and freshness on chain. Existing
ByrealClmm selection continues emitting legacy 13/14 and cannot represent
dynamic-fee pools. Market 29 requires the Prism deployment supporting this layout.