Serum: settle_funds after place_order
Avoid using anchor_spl::dex helpers, because calling serum through these functions costs significantly more compute, likely because AccountInfos need to be cloned twice. Examples: - new_order_v3: direct 26.8k CU, helpers 37.5k CU - settle funds: direct 24.9k CU, helpers 31.8k CU
This commit is contained in:
parent
57c06bc2da
commit
a40eb94833
|
@ -141,6 +141,8 @@ pub struct PlaceSerumOrder<'info> {
|
||||||
pub market_base_vault: UncheckedAccount<'info>,
|
pub market_base_vault: UncheckedAccount<'info>,
|
||||||
#[account(mut)]
|
#[account(mut)]
|
||||||
pub market_quote_vault: UncheckedAccount<'info>,
|
pub market_quote_vault: UncheckedAccount<'info>,
|
||||||
|
// needed for the automatic settle_funds call
|
||||||
|
pub market_vault_signer: UncheckedAccount<'info>,
|
||||||
|
|
||||||
// TODO: do we need to pass both, or just payer?
|
// TODO: do we need to pass both, or just payer?
|
||||||
// TODO: if we potentially settle immediately, they all need to be mut?
|
// TODO: if we potentially settle immediately, they all need to be mut?
|
||||||
|
@ -214,11 +216,11 @@ pub fn place_serum_order(
|
||||||
// TODO: pre-health check
|
// TODO: pre-health check
|
||||||
|
|
||||||
//
|
//
|
||||||
// Place the order
|
// Apply the order to serum. Also immediately settle, in case the order
|
||||||
|
// matched against an existing other order.
|
||||||
//
|
//
|
||||||
cpi_place_order(&ctx, &order.0)?;
|
cpi_place_order(&ctx, order.0)?;
|
||||||
|
cpi_settle_funds(&ctx)?;
|
||||||
// TODO: immediately call settle_funds?
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// After-order tracking
|
// After-order tracking
|
||||||
|
@ -255,47 +257,90 @@ pub fn place_serum_order(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cpi_place_order(ctx: &Context<PlaceSerumOrder>, order: &NewOrderInstructionV3) -> Result<()> {
|
fn cpi_place_order(ctx: &Context<PlaceSerumOrder>, order: NewOrderInstructionV3) -> Result<()> {
|
||||||
let order_payer_token_account = match order.side {
|
let order_payer_token_account = match order.side {
|
||||||
Side::Bid => ctx.accounts.quote_vault.to_account_info(),
|
Side::Bid => &ctx.accounts.quote_vault,
|
||||||
Side::Ask => ctx.accounts.base_vault.to_account_info(),
|
Side::Ask => &ctx.accounts.base_vault,
|
||||||
};
|
};
|
||||||
|
|
||||||
let context = CpiContext::new(
|
let data = serum_dex::instruction::MarketInstruction::NewOrderV3(order).pack();
|
||||||
ctx.accounts.serum_program.to_account_info(),
|
let instruction = solana_program::instruction::Instruction {
|
||||||
dex::NewOrderV3 {
|
program_id: *ctx.accounts.serum_program.key,
|
||||||
// generic accounts
|
data,
|
||||||
market: ctx.accounts.serum_market_external.to_account_info(),
|
accounts: vec![
|
||||||
request_queue: ctx.accounts.market_request_queue.to_account_info(),
|
AccountMeta::new(*ctx.accounts.serum_market_external.key, false),
|
||||||
event_queue: ctx.accounts.market_event_queue.to_account_info(),
|
AccountMeta::new(*ctx.accounts.open_orders.key, false),
|
||||||
market_bids: ctx.accounts.market_bids.to_account_info(),
|
AccountMeta::new(*ctx.accounts.market_request_queue.key, false),
|
||||||
market_asks: ctx.accounts.market_asks.to_account_info(),
|
AccountMeta::new(*ctx.accounts.market_event_queue.key, false),
|
||||||
coin_vault: ctx.accounts.market_base_vault.to_account_info(),
|
AccountMeta::new(*ctx.accounts.market_bids.key, false),
|
||||||
pc_vault: ctx.accounts.market_quote_vault.to_account_info(),
|
AccountMeta::new(*ctx.accounts.market_asks.key, false),
|
||||||
token_program: ctx.accounts.token_program.to_account_info(),
|
AccountMeta::new(order_payer_token_account.key(), false),
|
||||||
rent: ctx.accounts.rent.to_account_info(),
|
AccountMeta::new_readonly(ctx.accounts.group.key(), true),
|
||||||
|
AccountMeta::new(*ctx.accounts.market_base_vault.key, false),
|
||||||
// user accounts
|
AccountMeta::new(*ctx.accounts.market_quote_vault.key, false),
|
||||||
open_orders: ctx.accounts.open_orders.to_account_info(),
|
AccountMeta::new_readonly(*ctx.accounts.token_program.key, false),
|
||||||
// NOTE: this is also the user token account authority!
|
AccountMeta::new_readonly(ctx.accounts.group.key(), false),
|
||||||
open_orders_authority: ctx.accounts.group.to_account_info(),
|
],
|
||||||
order_payer_token_account,
|
};
|
||||||
},
|
let account_infos = [
|
||||||
);
|
ctx.accounts.serum_program.to_account_info(), // Have to add account of the program id
|
||||||
|
ctx.accounts.serum_market_external.to_account_info(),
|
||||||
|
ctx.accounts.open_orders.to_account_info(),
|
||||||
|
ctx.accounts.market_request_queue.to_account_info(),
|
||||||
|
ctx.accounts.market_event_queue.to_account_info(),
|
||||||
|
ctx.accounts.market_bids.to_account_info(),
|
||||||
|
ctx.accounts.market_asks.to_account_info(),
|
||||||
|
order_payer_token_account.to_account_info(),
|
||||||
|
ctx.accounts.group.to_account_info(),
|
||||||
|
ctx.accounts.market_base_vault.to_account_info(),
|
||||||
|
ctx.accounts.market_quote_vault.to_account_info(),
|
||||||
|
ctx.accounts.token_program.to_account_info(),
|
||||||
|
ctx.accounts.group.to_account_info(),
|
||||||
|
];
|
||||||
|
|
||||||
let group = ctx.accounts.group.load()?;
|
let group = ctx.accounts.group.load()?;
|
||||||
let seeds = group_seeds!(group);
|
let seeds = group_seeds!(group);
|
||||||
dex::new_order_v3(
|
solana_program::program::invoke_signed_unchecked(&instruction, &account_infos, &[seeds])?;
|
||||||
context.with_signer(&[seeds]),
|
|
||||||
order.side,
|
Ok(())
|
||||||
order.limit_price,
|
}
|
||||||
order.max_coin_qty,
|
|
||||||
order.max_native_pc_qty_including_fees,
|
fn cpi_settle_funds(ctx: &Context<PlaceSerumOrder>) -> Result<()> {
|
||||||
order.self_trade_behavior,
|
let data = serum_dex::instruction::MarketInstruction::SettleFunds.pack();
|
||||||
order.order_type,
|
let instruction = solana_program::instruction::Instruction {
|
||||||
order.client_order_id,
|
program_id: *ctx.accounts.serum_program.key,
|
||||||
order.limit,
|
data,
|
||||||
)?;
|
accounts: vec![
|
||||||
|
AccountMeta::new(*ctx.accounts.serum_market_external.key, false),
|
||||||
|
AccountMeta::new(*ctx.accounts.open_orders.key, false),
|
||||||
|
AccountMeta::new_readonly(ctx.accounts.group.key(), true),
|
||||||
|
AccountMeta::new(*ctx.accounts.market_base_vault.key, false),
|
||||||
|
AccountMeta::new(*ctx.accounts.market_quote_vault.key, false),
|
||||||
|
AccountMeta::new(ctx.accounts.base_vault.key(), false),
|
||||||
|
AccountMeta::new(ctx.accounts.quote_vault.key(), false),
|
||||||
|
AccountMeta::new_readonly(*ctx.accounts.market_vault_signer.key, false),
|
||||||
|
AccountMeta::new_readonly(*ctx.accounts.token_program.key, false),
|
||||||
|
AccountMeta::new(ctx.accounts.quote_vault.key(), false),
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
let account_infos = [
|
||||||
|
ctx.accounts.serum_market_external.to_account_info(),
|
||||||
|
ctx.accounts.serum_market_external.to_account_info(),
|
||||||
|
ctx.accounts.open_orders.to_account_info(),
|
||||||
|
ctx.accounts.group.to_account_info(),
|
||||||
|
ctx.accounts.market_base_vault.to_account_info(),
|
||||||
|
ctx.accounts.market_quote_vault.to_account_info(),
|
||||||
|
ctx.accounts.base_vault.to_account_info(),
|
||||||
|
ctx.accounts.quote_vault.to_account_info(),
|
||||||
|
ctx.accounts.market_vault_signer.to_account_info(),
|
||||||
|
ctx.accounts.token_program.to_account_info(),
|
||||||
|
ctx.accounts.quote_vault.to_account_info(),
|
||||||
|
];
|
||||||
|
|
||||||
|
let group = ctx.accounts.group.load()?;
|
||||||
|
let seeds = group_seeds!(group);
|
||||||
|
solana_program::program::invoke_signed_unchecked(&instruction, &account_infos, &[seeds])?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -808,6 +808,12 @@ impl<'keypair> ClientInstruction for PlaceSerumOrderInstruction<'keypair> {
|
||||||
let req_q = market_external.req_q;
|
let req_q = market_external.req_q;
|
||||||
let coin_vault = market_external.coin_vault;
|
let coin_vault = market_external.coin_vault;
|
||||||
let pc_vault = market_external.pc_vault;
|
let pc_vault = market_external.pc_vault;
|
||||||
|
let vault_signer = serum_dex::state::gen_vault_signer_key(
|
||||||
|
market_external.vault_signer_nonce,
|
||||||
|
&serum_market.serum_market_external,
|
||||||
|
&serum_market.serum_program,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let health_check_metas =
|
let health_check_metas =
|
||||||
derive_health_check_remaining_account_metas(&account_loader, &account, None, false)
|
derive_health_check_remaining_account_metas(&account_loader, &account, None, false)
|
||||||
|
@ -830,6 +836,7 @@ impl<'keypair> ClientInstruction for PlaceSerumOrderInstruction<'keypair> {
|
||||||
market_request_queue: from_serum_style_pubkey(&req_q),
|
market_request_queue: from_serum_style_pubkey(&req_q),
|
||||||
market_base_vault: from_serum_style_pubkey(&coin_vault),
|
market_base_vault: from_serum_style_pubkey(&coin_vault),
|
||||||
market_quote_vault: from_serum_style_pubkey(&pc_vault),
|
market_quote_vault: from_serum_style_pubkey(&pc_vault),
|
||||||
|
market_vault_signer: vault_signer,
|
||||||
owner: self.owner.pubkey(),
|
owner: self.owner.pubkey(),
|
||||||
token_program: Token::id(),
|
token_program: Token::id(),
|
||||||
rent: sysvar::rent::Rent::id(),
|
rent: sysvar::rent::Rent::id(),
|
||||||
|
|
Loading…
Reference in New Issue