release: update DEX protocol support for v4.0.9

Sync supported DEX IDLs from bitquery/solana-idl-lib, upgrade protocol builders, and keep trade submission hot paths free of RPC query calls.

Include exact-output coverage, token-account setup fixes for WSOL and stable pairs, and low-latency transaction build improvements.
This commit is contained in:
0xfnzero
2026-05-16 06:42:50 +08:00
parent f6db55c874
commit 05ac079d6d
57 changed files with 32699 additions and 588 deletions
+2
View File
@@ -75,6 +75,8 @@ pub struct SwapParams {
pub close_input_mint_ata: bool,
pub create_output_mint_ata: bool,
pub close_output_mint_ata: bool,
/// Fixed output amount. For protocols with exact-out instructions this selects exact-out
/// semantics and treats `input_amount` as the maximum input budget.
pub fixed_output_amount: Option<u64>,
pub gas_fee_strategy: GasFeeStrategy,
pub simulate: bool,
@@ -12,6 +12,11 @@ pub struct MeteoraDammV2Params {
pub token_b_mint: Pubkey,
pub token_a_program: Pubkey,
pub token_b_program: Pubkey,
pub referral_token_account: Option<Pubkey>,
/// `swap2` mode: 0 exact-in, 1 partial-fill (recommended default), 2 exact-out.
pub swap_mode: u8,
/// Include the instructions sysvar remaining account when the pool's rate limiter applies.
pub include_rate_limiter_sysvar: bool,
}
impl MeteoraDammV2Params {
@@ -32,9 +37,27 @@ impl MeteoraDammV2Params {
token_b_mint,
token_a_program,
token_b_program,
referral_token_account: None,
swap_mode: crate::instruction::utils::meteora_damm_v2::SWAP_MODE_PARTIAL_FILL,
include_rate_limiter_sysvar: false,
}
}
pub fn with_referral_token_account(mut self, referral_token_account: Pubkey) -> Self {
self.referral_token_account = Some(referral_token_account);
self
}
pub fn with_swap_mode(mut self, swap_mode: u8) -> Self {
self.swap_mode = swap_mode;
self
}
pub fn with_rate_limiter_sysvar(mut self, include: bool) -> Self {
self.include_rate_limiter_sysvar = include;
self
}
pub async fn from_pool_address_by_rpc(
rpc: &SolanaRpcClient,
pool_address: &Pubkey,
@@ -61,6 +84,9 @@ impl MeteoraDammV2Params {
token_b_mint: pool_data.token_b_mint,
token_a_program,
token_b_program,
referral_token_account: None,
swap_mode: crate::instruction::utils::meteora_damm_v2::SWAP_MODE_PARTIAL_FILL,
include_rate_limiter_sysvar: false,
})
}
}
+86 -1
View File
@@ -16,6 +16,26 @@ pub struct RaydiumAmmV4Params {
pub token_coin: Pubkey,
/// Pool's pc token account address
pub token_pc: Pubkey,
/// AMM open orders account
pub amm_open_orders: Pubkey,
/// AMM target orders account
pub amm_target_orders: Pubkey,
/// Serum/OpenBook program used by the AMM market
pub serum_program: Pubkey,
/// Serum/OpenBook market account
pub serum_market: Pubkey,
/// Serum/OpenBook bids account
pub serum_bids: Pubkey,
/// Serum/OpenBook asks account
pub serum_asks: Pubkey,
/// Serum/OpenBook event queue account
pub serum_event_queue: Pubkey,
/// Serum/OpenBook coin vault account
pub serum_coin_vault_account: Pubkey,
/// Serum/OpenBook pc vault account
pub serum_pc_vault_account: Pubkey,
/// Serum/OpenBook vault signer PDA
pub serum_vault_signer: Pubkey,
/// Current coin reserve amount in the pool
pub coin_reserve: u64,
/// Current pc reserve amount in the pool
@@ -32,13 +52,68 @@ impl RaydiumAmmV4Params {
coin_reserve: u64,
pc_reserve: u64,
) -> Self {
Self { amm, coin_mint, pc_mint, token_coin, token_pc, coin_reserve, pc_reserve }
Self {
amm,
coin_mint,
pc_mint,
token_coin,
token_pc,
amm_open_orders: Pubkey::default(),
amm_target_orders: Pubkey::default(),
serum_program: Pubkey::default(),
serum_market: Pubkey::default(),
serum_bids: Pubkey::default(),
serum_asks: Pubkey::default(),
serum_event_queue: Pubkey::default(),
serum_coin_vault_account: Pubkey::default(),
serum_pc_vault_account: Pubkey::default(),
serum_vault_signer: Pubkey::default(),
coin_reserve,
pc_reserve,
}
}
#[allow(clippy::too_many_arguments)]
pub fn with_market_accounts(
mut self,
amm_open_orders: Pubkey,
amm_target_orders: Pubkey,
serum_program: Pubkey,
serum_market: Pubkey,
serum_bids: Pubkey,
serum_asks: Pubkey,
serum_event_queue: Pubkey,
serum_coin_vault_account: Pubkey,
serum_pc_vault_account: Pubkey,
serum_vault_signer: Pubkey,
) -> Self {
self.amm_open_orders = amm_open_orders;
self.amm_target_orders = amm_target_orders;
self.serum_program = serum_program;
self.serum_market = serum_market;
self.serum_bids = serum_bids;
self.serum_asks = serum_asks;
self.serum_event_queue = serum_event_queue;
self.serum_coin_vault_account = serum_coin_vault_account;
self.serum_pc_vault_account = serum_pc_vault_account;
self.serum_vault_signer = serum_vault_signer;
self
}
pub async fn from_amm_address_by_rpc(
rpc: &SolanaRpcClient,
amm: Pubkey,
) -> Result<Self, anyhow::Error> {
let amm_info = crate::instruction::utils::raydium_amm_v4::fetch_amm_info(rpc, amm).await?;
let market_state =
crate::instruction::utils::raydium_amm_v4::fetch_market_state(rpc, amm_info.market)
.await?;
let serum_vault_signer =
crate::instruction::utils::raydium_amm_v4::derive_serum_vault_signer(
&amm_info.serum_dex,
&amm_info.market,
market_state.vault_signer_nonce,
)?;
let (coin_reserve, pc_reserve) =
get_multi_token_balances(rpc, &amm_info.token_coin, &amm_info.token_pc).await?;
Ok(Self {
@@ -47,6 +122,16 @@ impl RaydiumAmmV4Params {
pc_mint: amm_info.pc_mint,
token_coin: amm_info.token_coin,
token_pc: amm_info.token_pc,
amm_open_orders: amm_info.open_orders,
amm_target_orders: amm_info.target_orders,
serum_program: amm_info.serum_dex,
serum_market: amm_info.market,
serum_bids: market_state.serum_bids,
serum_asks: market_state.serum_asks,
serum_event_queue: market_state.serum_event_queue,
serum_coin_vault_account: market_state.serum_coin_vault_account,
serum_pc_vault_account: market_state.serum_pc_vault_account,
serum_vault_signer,
coin_reserve,
pc_reserve,
})